mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-04-11 02:20:20 +08:00
add unit test for flight microservice
This commit is contained in:
parent
c79be5a171
commit
112ffbc55b
@ -63,6 +63,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Ser
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Booking\tests\IntegrationTest\Integration.Test.csproj", "{50C66B53-ACA0-4AFF-8C5C-834D4EDA8FAC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unit.Test", "src\Services\Flight\tests\UnitTest\Unit.Test.csproj", "{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -99,6 +101,7 @@ Global
|
||||
{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2} = {295284BA-D4E4-40AA-A2C2-BE36343F7DE6}
|
||||
{539364C8-88B1-48A3-8406-D0B19FF30509} = {C1EBE17D-BFAD-47DA-88EB-BB073B84593E}
|
||||
{50C66B53-ACA0-4AFF-8C5C-834D4EDA8FAC} = {5185D5C5-0EAD-49D5-B405-93B939F3639B}
|
||||
{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8} = {C6EE337B-91EA-472A-87C7-E9528408CE59}
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A2D7C5C4-5148-4C3E-BB12-B7A197A290F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
@ -157,5 +160,9 @@ Global
|
||||
{50C66B53-ACA0-4AFF-8C5C-834D4EDA8FAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{50C66B53-ACA0-4AFF-8C5C-834D4EDA8FAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{50C66B53-ACA0-4AFF-8C5C-834D4EDA8FAC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8F78BCE2-C705-4357-A6B9-1B83B55ABBE8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@ -15,7 +15,7 @@ using Xunit.Abstractions;
|
||||
namespace Integration.Test;
|
||||
|
||||
[CollectionDefinition(nameof(IntegrationTestFixture))]
|
||||
public class SliceFixtureCollection : ICollectionFixture<IntegrationTestFixture>
|
||||
public class FixtureCollection : ICollectionFixture<IntegrationTestFixture>
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -6,8 +6,6 @@ public class CreateAircraftCommandValidator : AbstractValidator<CreateAircraftCo
|
||||
{
|
||||
public CreateAircraftCommandValidator()
|
||||
{
|
||||
CascadeMode = CascadeMode.Stop;
|
||||
|
||||
RuleFor(x => x.Model).NotEmpty().WithMessage("Model is required");
|
||||
RuleFor(x => x.Name).NotEmpty().WithMessage("Name is required");
|
||||
RuleFor(x => x.ManufacturingYear).NotEmpty().WithMessage("ManufacturingYear is required");
|
||||
|
||||
@ -6,8 +6,6 @@ public class CreateAirportCommandValidator : AbstractValidator<CreateAirportComm
|
||||
{
|
||||
public CreateAirportCommandValidator()
|
||||
{
|
||||
CascadeMode = CascadeMode.Stop;
|
||||
|
||||
RuleFor(x => x.Code).NotEmpty().WithMessage("Code is required");
|
||||
RuleFor(x => x.Name).NotEmpty().WithMessage("Name is required");
|
||||
RuleFor(x => x.Address).NotEmpty().WithMessage("Address is required");
|
||||
|
||||
@ -7,8 +7,6 @@ public class CreateFlightCommandValidator : AbstractValidator<CreateFlightComman
|
||||
{
|
||||
public CreateFlightCommandValidator()
|
||||
{
|
||||
CascadeMode = CascadeMode.Stop;
|
||||
|
||||
RuleFor(x => x.Price).GreaterThan(0).WithMessage("Price must be greater than 0");
|
||||
|
||||
RuleFor(x => x.Status).Must(p => (p.GetType().IsEnum &&
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
using AutoMapper;
|
||||
using Flight.Flights.Dtos;
|
||||
using Mapster;
|
||||
|
||||
namespace Flight.Flights.Features;
|
||||
|
||||
public class FlightMappings : IRegister
|
||||
public class FlightMappings : Profile
|
||||
{
|
||||
public void Register(TypeAdapterConfig config)
|
||||
{
|
||||
config.NewConfig<Models.Flight, FlightResponseDto>();
|
||||
}
|
||||
config.NewConfig<Models.Flight, FlightResponseDto>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,8 @@ public class CreateSeatCommandHandler : IRequestHandler<CreateSeatCommand, SeatR
|
||||
|
||||
var newSeat = await _flightDbContext.Seats.AddAsync(seatEntity, cancellationToken);
|
||||
|
||||
await _flightDbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return _mapper.Map<SeatResponseDto>(newSeat.Entity);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,8 +8,6 @@ public class CreateSeatCommandValidator : AbstractValidator<CreateSeatCommand>
|
||||
{
|
||||
public CreateSeatCommandValidator()
|
||||
{
|
||||
CascadeMode = CascadeMode.Stop;
|
||||
|
||||
RuleFor(x => x.SeatNumber).NotEmpty().WithMessage("SeatNumber is required");
|
||||
RuleFor(x => x.FlightId).NotEmpty().WithMessage("FlightId is required");
|
||||
RuleFor(x => x.Class).Must(p => (p.GetType().IsEnum &&
|
||||
|
||||
@ -5,9 +5,9 @@ namespace Integration.Test.Fakes;
|
||||
|
||||
public static class FakeSeatCreated
|
||||
{
|
||||
public static Seat Generate(CreateSeatCommand command)
|
||||
public static global::Flight.Seats.Models.Seat Generate(CreateSeatCommand command)
|
||||
{
|
||||
return Seat.Create(command.Id, command.SeatNumber, command.Type, command.Class, command.FlightId);
|
||||
return global::Flight.Seats.Models.Seat.Create(command.Id, command.SeatNumber, command.Type, command.Class, command.FlightId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ using Xunit.Abstractions;
|
||||
namespace Integration.Test;
|
||||
|
||||
[CollectionDefinition(nameof(IntegrationTestFixture))]
|
||||
public class SliceFixtureCollection : ICollectionFixture<IntegrationTestFixture> { }
|
||||
public class FixtureCollection : ICollectionFixture<IntegrationTestFixture> { }
|
||||
|
||||
public class IntegrationTestFixture : IAsyncLifetime
|
||||
{
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.Contracts.Grpc;
|
||||
using Flight.Flights.Features.GetAvailableFlights;
|
||||
using FluentAssertions;
|
||||
using Grpc.Net.Client;
|
||||
using Integration.Test.Fakes;
|
||||
using MagicOnion.Client;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test.Flight.Features;
|
||||
namespace Integration.Test.Seat.Features;
|
||||
|
||||
[Collection(nameof(IntegrationTestFixture))]
|
||||
public class GetAvailableSeatsTests
|
||||
@ -36,7 +35,7 @@ public class GetAvailableSeatsTests
|
||||
var seatEntity1 = FakeSeatCreated.Generate(seatCommand1);
|
||||
var seatEntity2 = FakeSeatCreated.Generate(seatCommand2);
|
||||
|
||||
await _fixture.InsertAsync(seatEntity1, seatEntity2);
|
||||
await _fixture.InsertAsync<global::Flight.Seats.Models.Seat, global::Flight.Seats.Models.Seat>(seatEntity1, seatEntity2);
|
||||
|
||||
var flightGrpcClient = MagicOnionClient.Create<IFlightGrpcService>(_channel);
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.Contracts.Grpc;
|
||||
using FluentAssertions;
|
||||
using Grpc.Net.Client;
|
||||
@ -7,7 +6,7 @@ using Integration.Test.Fakes;
|
||||
using MagicOnion.Client;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test.Flight.Features;
|
||||
namespace Integration.Test.Seat.Features;
|
||||
|
||||
[Collection(nameof(IntegrationTestFixture))]
|
||||
public class ReserveSeatTests
|
||||
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flight.Aircrafts.Dtos;
|
||||
using Flight.Aircrafts.Features.CreateAircraft;
|
||||
using FluentAssertions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Unit.Test.Common;
|
||||
using Unit.Test.Fakes;
|
||||
using Xunit;
|
||||
|
||||
namespace Unit.Test.Aircraft.Features.CreateAircraftTests;
|
||||
|
||||
[Collection(nameof(UnitTestFixture))]
|
||||
public class CreateAircraftCommandHandlerTests
|
||||
{
|
||||
private readonly UnitTestFixture _fixture;
|
||||
private readonly CreateAircraftCommandHandler _handler;
|
||||
|
||||
public Task<AircraftResponseDto> Act(CreateAircraftCommand command, CancellationToken cancellationToken) =>
|
||||
_handler.Handle(command, cancellationToken);
|
||||
|
||||
public CreateAircraftCommandHandlerTests(UnitTestFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_handler = new CreateAircraftCommandHandler(_fixture.Mapper, _fixture.DbContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task handler_with_valid_command_should_create_new_aircraft_and_return_currect_aircraft_dto()
|
||||
{
|
||||
// Arrange
|
||||
var command = new FakeCreateAircraftCommand().Generate();
|
||||
|
||||
// Act
|
||||
var response = await Act(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var entity = await _fixture.DbContext.Aircraft.SingleOrDefaultAsync(x => x.Model == response.Model);
|
||||
|
||||
entity?.Should().NotBeNull();
|
||||
response?.Model.Should().Be(entity?.Model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task handler_with_null_command_should_throw_argument_exception()
|
||||
{
|
||||
// Arrange
|
||||
CreateAircraftCommand command = null;
|
||||
|
||||
// Act
|
||||
Func<Task> act = async () => { await Act(command, CancellationToken.None); };
|
||||
|
||||
// Assert
|
||||
await act.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
using Flight.Aircrafts.Features.CreateAircraft;
|
||||
using FluentAssertions;
|
||||
using FluentValidation.TestHelper;
|
||||
using Unit.Test.Common;
|
||||
using Unit.Test.Fakes;
|
||||
using Xunit;
|
||||
|
||||
namespace Unit.Test.Aircraft.Features.CreateAircraftTests;
|
||||
|
||||
[Collection(nameof(UnitTestFixture))]
|
||||
public class CreateAircraftCommandValidatorTests
|
||||
{
|
||||
[Fact]
|
||||
public void is_valid_should_be_false_when_have_invalid_parameter()
|
||||
{
|
||||
// Arrange
|
||||
var command = new FakeValidateCreateAircraftCommand().Generate();
|
||||
var validator = new CreateAircraftCommandValidator();
|
||||
|
||||
// Act
|
||||
var result = validator.TestValidate(command);
|
||||
|
||||
// Assert
|
||||
result.IsValid.Should().BeFalse();
|
||||
result.ShouldHaveValidationErrorFor(x => x.Model);
|
||||
result.ShouldHaveValidationErrorFor(x => x.ManufacturingYear);
|
||||
result.ShouldHaveValidationErrorFor(x => x.Name);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flight.Airports.Dtos;
|
||||
using Flight.Airports.Features.CreateAirport;
|
||||
using FluentAssertions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Unit.Test.Common;
|
||||
using Unit.Test.Fakes;
|
||||
using Xunit;
|
||||
|
||||
namespace Unit.Test.Airport.Features.CreateAirportTests;
|
||||
|
||||
[Collection(nameof(UnitTestFixture))]
|
||||
public class CreateAirportCommandHandlerTests
|
||||
{
|
||||
private readonly UnitTestFixture _fixture;
|
||||
private readonly CreateAirportCommandHandler _handler;
|
||||
|
||||
|
||||
public CreateAirportCommandHandlerTests(UnitTestFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_handler = new CreateAirportCommandHandler(_fixture.Mapper, _fixture.DbContext);
|
||||
}
|
||||
|
||||
public Task<AirportResponseDto> Act(CreateAirportCommand command, CancellationToken cancellationToken) =>
|
||||
_handler.Handle(command, cancellationToken);
|
||||
|
||||
[Fact]
|
||||
public async Task handler_with_valid_command_should_create_new_airport_and_return_currect_airport_dto()
|
||||
{
|
||||
// Arrange
|
||||
var command = new FakeCreateAirportCommand().Generate();
|
||||
|
||||
// Act
|
||||
var response = await Act(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var entity = await _fixture.DbContext.Airports.SingleOrDefaultAsync(x => x.Code == response.Code);
|
||||
|
||||
entity?.Should().NotBeNull();
|
||||
response?.Code.Should().Be(entity?.Code);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task handler_with_null_command_should_throw_argument_exception()
|
||||
{
|
||||
// Arrange
|
||||
CreateAirportCommand command = null;
|
||||
|
||||
// Act
|
||||
var act = async () => { await Act(command, CancellationToken.None); };
|
||||
|
||||
// Assert
|
||||
await act.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
using Flight.Airports.Features.CreateAirport;
|
||||
using FluentAssertions;
|
||||
using FluentValidation.TestHelper;
|
||||
using Unit.Test.Common;
|
||||
using Unit.Test.Fakes;
|
||||
using Xunit;
|
||||
|
||||
namespace Unit.Test.Airport.Features.CreateAirportTests;
|
||||
|
||||
[Collection(nameof(UnitTestFixture))]
|
||||
public class CreateAirportCommandValidatorTests
|
||||
{
|
||||
[Fact]
|
||||
public void is_valid_should_be_false_when_have_invalid_parameter()
|
||||
{
|
||||
// Arrange
|
||||
var command = new FakeValidateCreateAirportCommand().Generate();
|
||||
var validator = new CreateAirportCommandValidator();
|
||||
|
||||
// Act
|
||||
var result = validator.TestValidate(command);
|
||||
|
||||
// Assert
|
||||
result.IsValid.Should().BeFalse();
|
||||
result.ShouldHaveValidationErrorFor(x => x.Code);
|
||||
result.ShouldHaveValidationErrorFor(x => x.Address);
|
||||
result.ShouldHaveValidationErrorFor(x => x.Name);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Flight.Aircrafts.Models;
|
||||
using Flight.Airports.Models;
|
||||
using Flight.Data;
|
||||
using Flight.Flights.Models;
|
||||
using Flight.Seats.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Unit.Test.Common
|
||||
{
|
||||
public static class DbContextFactory
|
||||
{
|
||||
public static FlightDbContext Create()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<FlightDbContext>()
|
||||
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()).Options;
|
||||
|
||||
var context = new FlightDbContext(options, httpContextAccessor: null);
|
||||
|
||||
// Seed our data
|
||||
FlightDataSeeder(context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
private static void FlightDataSeeder(FlightDbContext context)
|
||||
{
|
||||
var airports = new List<global::Flight.Airports.Models.Airport>
|
||||
{
|
||||
global::Flight.Airports.Models.Airport.Create(1, "Lisbon International Airport", "LIS", "12988"),
|
||||
global::Flight.Airports.Models.Airport.Create(2, "Sao Paulo International Airport", "BRZ", "11200")
|
||||
};
|
||||
|
||||
context.Airports.AddRange(airports);
|
||||
|
||||
var aircrafts = new List<global::Flight.Aircrafts.Models.Aircraft>
|
||||
{
|
||||
global::Flight.Aircrafts.Models.Aircraft.Create(1, "Boeing 737", "B737", 2005),
|
||||
global::Flight.Aircrafts.Models.Aircraft.Create(2, "Airbus 300", "A300", 2000),
|
||||
global::Flight.Aircrafts.Models.Aircraft.Create(3, "Airbus 320", "A320", 2003)
|
||||
};
|
||||
|
||||
context.Aircraft.AddRange(aircrafts);
|
||||
|
||||
var flights = new List<global::Flight.Flights.Models.Flight>
|
||||
{
|
||||
global::Flight.Flights.Models.Flight.Create(1, "BD467", 1, 1, new DateTime(2022, 1, 31, 12, 0, 0),
|
||||
new DateTime(2022, 1, 31, 14, 0, 0),
|
||||
2, 120m,
|
||||
new DateTime(2022, 1, 31), FlightStatus.Completed,
|
||||
8000)
|
||||
};
|
||||
context.Flights.AddRange(flights);
|
||||
|
||||
var seats = new List<global::Flight.Seats.Models.Seat>
|
||||
{
|
||||
global::Flight.Seats.Models.Seat.Create(1, "12A", SeatType.Window, SeatClass.Economy, 1),
|
||||
global::Flight.Seats.Models.Seat.Create(2, "12B", SeatType.Window, SeatClass.Economy, 1),
|
||||
global::Flight.Seats.Models.Seat.Create(3, "12C", SeatType.Middle, SeatClass.Economy, 1),
|
||||
global::Flight.Seats.Models.Seat.Create(4, "12D", SeatType.Middle, SeatClass.Economy, 1),
|
||||
global::Flight.Seats.Models.Seat.Create(5, "12E", SeatType.Aisle, SeatClass.Economy, 1),
|
||||
global::Flight.Seats.Models.Seat.Create(6, "12F", SeatType.Aisle, SeatClass.Economy, 1)
|
||||
};
|
||||
|
||||
context.Seats.AddRange(seats);
|
||||
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public static void Destroy(FlightDbContext context)
|
||||
{
|
||||
context.Database.EnsureDeleted();
|
||||
context.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/Services/Flight/tests/UnitTest/Common/MapperFactory.cs
Normal file
18
src/Services/Flight/tests/UnitTest/Common/MapperFactory.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using Flight;
|
||||
using Mapster;
|
||||
using MapsterMapper;
|
||||
|
||||
namespace Unit.Test.Common
|
||||
{
|
||||
public static class MapperFactory
|
||||
{
|
||||
public static IMapper Create()
|
||||
{
|
||||
var typeAdapterConfig = TypeAdapterConfig.GlobalSettings;
|
||||
typeAdapterConfig.Scan(typeof(FlightRoot).Assembly);
|
||||
IMapper instance = new Mapper(typeAdapterConfig);
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
|
||||
namespace Unit.Test.Common;
|
||||
|
||||
public static class SnowFlakIdGeneratorFactory
|
||||
{
|
||||
public static void Create()
|
||||
{
|
||||
SnowFlakIdGenerator.Configure(1);
|
||||
}
|
||||
}
|
||||
29
src/Services/Flight/tests/UnitTest/Common/UnitTestFixture.cs
Normal file
29
src/Services/Flight/tests/UnitTest/Common/UnitTestFixture.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Flight.Data;
|
||||
using MapsterMapper;
|
||||
using Xunit;
|
||||
|
||||
namespace Unit.Test.Common
|
||||
{
|
||||
[CollectionDefinition(nameof(UnitTestFixture))]
|
||||
public class FixtureCollection : ICollectionFixture<UnitTestFixture> { }
|
||||
|
||||
public class UnitTestFixture : IDisposable
|
||||
{
|
||||
public UnitTestFixture()
|
||||
{
|
||||
SnowFlakIdGeneratorFactory.Create();
|
||||
Mapper = MapperFactory.Create();
|
||||
DbContext = DbContextFactory.Create();
|
||||
}
|
||||
|
||||
public IMapper Mapper { get; }
|
||||
public FlightDbContext DbContext { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DbContextFactory.Destroy(DbContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
using AutoBogus;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Flight.Aircrafts.Features.CreateAircraft;
|
||||
|
||||
namespace Unit.Test.Fakes;
|
||||
|
||||
public class FakeCreateAircraftCommand : AutoFaker<CreateAircraftCommand>
|
||||
{
|
||||
public FakeCreateAircraftCommand()
|
||||
{
|
||||
RuleFor(r => r.Id, _ => SnowFlakIdGenerator.NewId());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
using AutoBogus;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Flight.Airports.Features.CreateAirport;
|
||||
|
||||
namespace Unit.Test.Fakes;
|
||||
|
||||
public class FakeCreateAirportCommand : AutoFaker<CreateAirportCommand>
|
||||
{
|
||||
public FakeCreateAirportCommand()
|
||||
{
|
||||
RuleFor(r => r.Id, _ => SnowFlakIdGenerator.NewId());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
using AutoBogus;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Flight.Flights.Features.CreateFlight;
|
||||
|
||||
namespace Unit.Test.Fakes;
|
||||
|
||||
public sealed class FakeCreateFlightCommand : AutoFaker<CreateFlightCommand>
|
||||
{
|
||||
public FakeCreateFlightCommand()
|
||||
{
|
||||
RuleFor(r => r.Id, _ => SnowFlakIdGenerator.NewId());
|
||||
RuleFor(r => r.FlightNumber, r => r.Random.String());
|
||||
RuleFor(r => r.DepartureAirportId, _ => 1);
|
||||
RuleFor(r => r.ArriveAirportId, _ => 2);
|
||||
RuleFor(r => r.AircraftId, _ => 1);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
using AutoBogus;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Flight.Seats.Features.CreateSeat;
|
||||
using Flight.Seats.Models;
|
||||
|
||||
namespace Unit.Test.Fakes;
|
||||
|
||||
public class FakeCreateSeatCommand : AutoFaker<CreateSeatCommand>
|
||||
{
|
||||
public FakeCreateSeatCommand()
|
||||
{
|
||||
RuleFor(r => r.Id, _ => SnowFlakIdGenerator.NewId());
|
||||
RuleFor(r => r.FlightId, _ => 1);
|
||||
RuleFor(r => r.SeatNumber, _ => "F99");
|
||||
RuleFor(r => r.Type, _ => SeatType.Window);
|
||||
RuleFor(r => r.Class, _ => SeatClass.Economy);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
using AutoBogus;
|
||||
using Flight.Aircrafts.Features.CreateAircraft;
|
||||
|
||||
namespace Unit.Test.Fakes;
|
||||
|
||||
public class FakeValidateCreateAircraftCommand : AutoFaker<CreateAircraftCommand>
|
||||
{
|
||||
public FakeValidateCreateAircraftCommand()
|
||||
{
|
||||
RuleFor(r => r.ManufacturingYear, _ => 0);
|
||||
RuleFor(r => r.Name, _ => null);
|
||||
RuleFor(r => r.Model, _ => null);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
using AutoBogus;
|
||||
using Flight.Airports.Features.CreateAirport;
|
||||
|
||||
namespace Unit.Test.Fakes;
|
||||
|
||||
public class FakeValidateCreateAirportCommand : AutoFaker<CreateAirportCommand>
|
||||
{
|
||||
public FakeValidateCreateAirportCommand()
|
||||
{
|
||||
RuleFor(r => r.Code, _ => null);
|
||||
RuleFor(r => r.Name, _ => null);
|
||||
RuleFor(r => r.Address, _ => null);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using AutoBogus;
|
||||
using Flight.Flights.Features.CreateFlight;
|
||||
using Flight.Flights.Models;
|
||||
|
||||
namespace Unit.Test.Fakes;
|
||||
|
||||
public class FakeValidateCreateFlightCommand : AutoFaker<CreateFlightCommand>
|
||||
{
|
||||
public FakeValidateCreateFlightCommand()
|
||||
{
|
||||
RuleFor(r => r.Price, _ => -10);
|
||||
RuleFor(r => r.Status, _ => (FlightStatus)10);
|
||||
RuleFor(r => r.AircraftId, _ => 0);
|
||||
RuleFor(r => r.DepartureAirportId, _ => 0);
|
||||
RuleFor(r => r.ArriveAirportId, _ => 0);
|
||||
RuleFor(r => r.DurationMinutes, _ => 0);
|
||||
RuleFor(r => r.FlightDate, _ => new DateTime());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
using AutoBogus;
|
||||
using Flight.Seats.Features.CreateSeat;
|
||||
using Flight.Seats.Models;
|
||||
|
||||
namespace Unit.Test.Fakes;
|
||||
|
||||
public class FakeValidateCreateSeatCommand : AutoFaker<CreateSeatCommand>
|
||||
{
|
||||
public FakeValidateCreateSeatCommand()
|
||||
{
|
||||
RuleFor(r => r.SeatNumber, _ => null);
|
||||
RuleFor(r => r.FlightId, _ => 0);
|
||||
RuleFor(r => r.Class, _ => (SeatClass)10);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flight.Flights.Dtos;
|
||||
using Flight.Flights.Features.CreateFlight;
|
||||
using FluentAssertions;
|
||||
using Unit.Test.Common;
|
||||
using Unit.Test.Fakes;
|
||||
using Xunit;
|
||||
|
||||
namespace Unit.Test.Flight.Features.CreateFlight;
|
||||
|
||||
[Collection(nameof(UnitTestFixture))]
|
||||
public class CreateFlightCommandHandlerTests
|
||||
{
|
||||
private readonly UnitTestFixture _fixture;
|
||||
private readonly CreateFlightCommandHandler _handler;
|
||||
|
||||
public Task<FlightResponseDto> Act(CreateFlightCommand command, CancellationToken cancellationToken) =>
|
||||
_handler.Handle(command, cancellationToken);
|
||||
|
||||
public CreateFlightCommandHandlerTests(UnitTestFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_handler = new CreateFlightCommandHandler(fixture.Mapper, fixture.DbContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task handler_with_valid_command_should_create_new_flight_and_return_currect_flight_dto()
|
||||
{
|
||||
// Arrange
|
||||
var command = new FakeCreateFlightCommand().Generate();
|
||||
|
||||
// Act
|
||||
var response = await Act(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var entity = await _fixture.DbContext.Flights.FindAsync(response?.Id);
|
||||
|
||||
entity?.Should().NotBeNull();
|
||||
response?.Id.Should().Be(entity?.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task handler_with_null_command_should_throw_argument_exception()
|
||||
{
|
||||
// Arrange
|
||||
CreateFlightCommand command = null;
|
||||
|
||||
// Act
|
||||
Func<Task> act = async () => { await Act(command, CancellationToken.None); };
|
||||
|
||||
// Assert
|
||||
await act.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
using Flight.Flights.Features.CreateFlight;
|
||||
using FluentAssertions;
|
||||
using FluentValidation.TestHelper;
|
||||
using Unit.Test.Common;
|
||||
using Unit.Test.Fakes;
|
||||
using Xunit;
|
||||
|
||||
namespace Unit.Test.Flight.Features.CreateFlight;
|
||||
|
||||
[Collection(nameof(UnitTestFixture))]
|
||||
public class CreateFlightCommandValidatorTests
|
||||
{
|
||||
[Fact]
|
||||
public void is_valid_should_be_false_when_have_invalid_parameter()
|
||||
{
|
||||
// Arrange
|
||||
var command = new FakeValidateCreateFlightCommand().Generate();
|
||||
var validator = new CreateFlightCommandValidator();
|
||||
|
||||
// Act
|
||||
var result = validator.TestValidate(command);
|
||||
|
||||
// Assert
|
||||
result.IsValid.Should().BeFalse();
|
||||
result.ShouldHaveValidationErrorFor(x => x.Price);
|
||||
result.ShouldHaveValidationErrorFor(x => x.Status);
|
||||
result.ShouldHaveValidationErrorFor(x => x.AircraftId);
|
||||
result.ShouldHaveValidationErrorFor(x => x.DepartureAirportId);
|
||||
result.ShouldHaveValidationErrorFor(x => x.ArriveAirportId);
|
||||
result.ShouldHaveValidationErrorFor(x => x.DurationMinutes);
|
||||
result.ShouldHaveValidationErrorFor(x => x.FlightDate);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Flight.Flights.Dtos;
|
||||
using MapsterMapper;
|
||||
using Unit.Test.Common;
|
||||
using Xunit;
|
||||
|
||||
namespace Unit.Test.Flight;
|
||||
|
||||
[Collection(nameof(UnitTestFixture))]
|
||||
public class FlightMappingTests
|
||||
{
|
||||
private readonly UnitTestFixture _fixture;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public FlightMappingTests(UnitTestFixture fixture)
|
||||
{
|
||||
_mapper = fixture.Mapper;
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> Data
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new object[]
|
||||
{
|
||||
// these types will instantiate with reflection in the future
|
||||
typeof(global::Flight.Flights.Models.Flight), typeof(FlightResponseDto)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(Data))]
|
||||
public void should_support_mapping_from_source_to_destination(Type source, Type destination,
|
||||
params object[] parameters)
|
||||
{
|
||||
var instance = Activator.CreateInstance(source, parameters);
|
||||
|
||||
_mapper.Map(instance, source, destination);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flight.Seats.Dtos;
|
||||
using Flight.Seats.Features.CreateSeat;
|
||||
using FluentAssertions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Unit.Test.Common;
|
||||
using Unit.Test.Fakes;
|
||||
using Xunit;
|
||||
|
||||
namespace Unit.Test.Seat.Features;
|
||||
|
||||
[Collection(nameof(UnitTestFixture))]
|
||||
public class CreateSeatCommandHandlerTests
|
||||
{
|
||||
private readonly UnitTestFixture _fixture;
|
||||
private readonly CreateSeatCommandHandler _handler;
|
||||
|
||||
|
||||
public CreateSeatCommandHandlerTests(UnitTestFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_handler = new CreateSeatCommandHandler(_fixture.Mapper, _fixture.DbContext);
|
||||
}
|
||||
|
||||
public Task<SeatResponseDto> Act(CreateSeatCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
return _handler.Handle(command, cancellationToken);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task handler_with_valid_command_should_create_new_seat_and_return_currect_seat_dto()
|
||||
{
|
||||
// Arrange
|
||||
var command = new FakeCreateSeatCommand().Generate();
|
||||
|
||||
// Act
|
||||
var response = await Act(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var entity = await _fixture.DbContext.Seats.SingleOrDefaultAsync(x => x.SeatNumber == response.SeatNumber);
|
||||
|
||||
entity?.Should().NotBeNull();
|
||||
response?.Id.Should().Be(entity?.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task handler_with_null_command_should_throw_argument_exception()
|
||||
{
|
||||
// Arrange
|
||||
CreateSeatCommand command = null;
|
||||
|
||||
// Act
|
||||
var act = async () => { await Act(command, CancellationToken.None); };
|
||||
|
||||
// Assert
|
||||
await act.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
using Flight.Seats.Features.CreateSeat;
|
||||
using FluentAssertions;
|
||||
using FluentValidation.TestHelper;
|
||||
using Unit.Test.Common;
|
||||
using Unit.Test.Fakes;
|
||||
using Xunit;
|
||||
|
||||
namespace Unit.Test.Seat.Features;
|
||||
|
||||
[Collection(nameof(UnitTestFixture))]
|
||||
public class CreateSeatCommandValidatorTests
|
||||
{
|
||||
[Fact]
|
||||
public void is_valid_should_be_false_when_have_invalid_parameter()
|
||||
{
|
||||
// Arrange
|
||||
var command = new FakeValidateCreateSeatCommand().Generate();
|
||||
var validator = new CreateSeatCommandValidator();
|
||||
|
||||
// Act
|
||||
var result = validator.TestValidate(command);
|
||||
|
||||
// Assert
|
||||
result.IsValid.Should().BeFalse();
|
||||
result.ShouldHaveValidationErrorFor(x => x.SeatNumber);
|
||||
result.ShouldHaveValidationErrorFor(x => x.FlightId);
|
||||
result.ShouldHaveValidationErrorFor(x => x.Class);
|
||||
}
|
||||
}
|
||||
42
src/Services/Flight/tests/UnitTest/Seat/SeatMappingTests.cs
Normal file
42
src/Services/Flight/tests/UnitTest/Seat/SeatMappingTests.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Flight.Seats.Dtos;
|
||||
using MapsterMapper;
|
||||
using Unit.Test.Common;
|
||||
using Xunit;
|
||||
|
||||
namespace Unit.Test.Seat;
|
||||
|
||||
[Collection(nameof(UnitTestFixture))]
|
||||
public class SeatMappingTests
|
||||
{
|
||||
private readonly UnitTestFixture _fixture;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public SeatMappingTests(UnitTestFixture fixture)
|
||||
{
|
||||
_mapper = fixture.Mapper;
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> Data
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new object[]
|
||||
{
|
||||
// these types will instantiate with reflection in the future
|
||||
typeof(global::Flight.Seats.Models.Seat), typeof(SeatResponseDto)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(Data))]
|
||||
public void should_support_mapping_from_source_to_destination(Type source, Type destination, params object[] parameters)
|
||||
{
|
||||
var instance = Activator.CreateInstance(source, parameters);
|
||||
|
||||
_mapper.Map(instance, source, destination);
|
||||
}
|
||||
}
|
||||
25
src/Services/Flight/tests/UnitTest/Unit.Test.csproj
Normal file
25
src/Services/Flight/tests/UnitTest/Unit.Test.csproj
Normal file
@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Flight.Api\Flight.Api.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@ -19,7 +19,7 @@ using Xunit.Abstractions;
|
||||
namespace Integration.Test;
|
||||
|
||||
[CollectionDefinition(nameof(IntegrationTestFixture))]
|
||||
public class SliceFixtureCollection : ICollectionFixture<IntegrationTestFixture> { }
|
||||
public class FixtureCollection : ICollectionFixture<IntegrationTestFixture> { }
|
||||
|
||||
public class IntegrationTestFixture : IAsyncLifetime
|
||||
{
|
||||
|
||||
@ -27,7 +27,7 @@ using Xunit.Abstractions;
|
||||
namespace Integration.Test;
|
||||
|
||||
[CollectionDefinition(nameof(IntegrationTestFixture))]
|
||||
public class SliceFixtureCollection : ICollectionFixture<IntegrationTestFixture> { }
|
||||
public class FixtureCollection : ICollectionFixture<IntegrationTestFixture> { }
|
||||
|
||||
public class IntegrationTestFixture : IAsyncLifetime
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user