feat:add end to end test for flight

This commit is contained in:
a.kafrashian 2025-05-05 15:48:54 +03:30
parent 1fb9558227
commit 68d9db7849
11 changed files with 262 additions and 1 deletions

View File

@ -9,10 +9,10 @@ var builder = WebApplication.CreateBuilder(args);
builder.AddSharedInfrastructure();
builder.AddFlightModules();
builder.AddIdentityModules();
builder.AddPassengerModules();
builder.AddBookingModules();
builder.AddFlightModules();
var app = builder.Build();

View File

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<None Update="xunit.runner.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\Api\src\Api.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,21 @@
using AutoBogus;
using Flight.Flights.Enums;
namespace EndToEnd.Test.Fakes;
using global::Flight.Data.Seed;
using global::Flight.Flights.Features.CreatingFlight.V1;
using MassTransit;
public sealed class FakeCreateFlightCommand : AutoFaker<CreateFlight>
{
public FakeCreateFlightCommand()
{
RuleFor(r => r.Id, _ => NewId.NextGuid());
RuleFor(r => r.FlightNumber, r => "12FF");
RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id);
RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id);
RuleFor(r => r.Status, _ => FlightStatus.Flying);
RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id);
}
}

View File

@ -0,0 +1,22 @@
namespace EndToEnd.Test.Fakes;
using AutoBogus;
using global::Flight.Data.Seed;
using global::Flight.Flights.Enums;
using global::Flight.Flights.Features.CreatingFlight.V1;
using MassTransit;
public sealed class FakeCreateFlightMongoCommand : AutoFaker<CreateFlightMongo>
{
public FakeCreateFlightMongoCommand()
{
RuleFor(r => r.Id, _ => NewId.NextGuid());
RuleFor(r => r.FlightNumber, r => "12FF");
RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id);
RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id);
RuleFor(r => r.Status, _ => FlightStatus.Flying);
RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id);
RuleFor(r => r.IsDeleted, _ => false);
}
}

View File

@ -0,0 +1,33 @@
using System.Net;
using System.Net.Http.Json;
using Api;
using BuildingBlocks.TestBase;
using EndToEnd.Test.Fakes;
using EndToEnd.Test.Routes;
using Flight.Data;
using FluentAssertions;
using Xunit;
namespace EndToEnd.Test.Flight.Features;
public class CreateFlightTests : FlightEndToEndTestBase
{
public CreateFlightTests(TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)
{
}
[Fact]
public async Task should_create_new_flight_to_db_and_publish_message_to_broker()
{
//Arrange
var command = new FakeCreateFlightCommand().Generate();
// Act
var route = ApiRoutes.Flight.CreateFlight;
var result = await Fixture.HttpClient.PostAsJsonAsync(route, command);
// Assert
result.StatusCode.Should().Be(HttpStatusCode.Created);
}
}

View File

@ -0,0 +1,34 @@
using System.Net;
using Api;
using BuildingBlocks.TestBase;
using EndToEnd.Test.Fakes;
using EndToEnd.Test.Routes;
using Flight.Data;
using FluentAssertions;
using Xunit;
namespace EndToEnd.Test.Flight.Features;
public class GetFlightByIdTests : FlightEndToEndTestBase
{
public GetFlightByIdTests(TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)
{
}
[Fact]
public async Task should_retrive_a_flight_by_id_currectly()
{
//Arrange
var command = new FakeCreateFlightMongoCommand().Generate();
await Fixture.SendAsync(command);
// Act
var route = ApiRoutes.Flight.GetFlightById.Replace(ApiRoutes.Flight.Id, command.Id.ToString(), StringComparison.CurrentCulture);
var result = await Fixture.HttpClient.GetAsync(route);
// Assert
result.StatusCode.Should().Be(HttpStatusCode.OK);
}
}

View File

@ -0,0 +1,20 @@
using Api;
using BuildingBlocks.TestBase;
using Flight.Data;
using Xunit;
namespace EndToEnd.Test;
[Collection(EndToEndTestCollection.Name)]
public class FlightEndToEndTestBase : TestBase<Program, FlightDbContext, FlightReadDbContext>
{
public FlightEndToEndTestBase(TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)
{
}
}
[CollectionDefinition(Name)]
public class EndToEndTestCollection : ICollectionFixture<TestFixture<Program, FlightDbContext, FlightReadDbContext>>
{
public const string Name = "Flight EndToEnd Test";
}

View File

@ -0,0 +1,85 @@
using BuildingBlocks.EFCore;
using Flight.Aircrafts.Models;
using Flight.Airports.Models;
using Flight.Data;
using Flight.Data.Seed;
using Flight.Flights.Models;
using Flight.Seats.Models;
using MapsterMapper;
using Microsoft.EntityFrameworkCore;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
namespace EndToEnd.Test;
public class FlightTestDataSeeder(
FlightDbContext flightDbContext,
FlightReadDbContext flightReadDbContext,
IMapper mapper
) : ITestDataSeeder
{
public async Task SeedAllAsync()
{
await SeedAirportAsync();
await SeedAircraftAsync();
await SeedFlightAsync();
await SeedSeatAsync();
}
private async Task SeedAirportAsync()
{
if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Airports))
{
await flightDbContext.Airports.AddRangeAsync(InitialData.Airports);
await flightDbContext.SaveChangesAsync();
if (!await MongoQueryable.AnyAsync(flightReadDbContext.Airport.AsQueryable()))
{
await flightReadDbContext.Airport.InsertManyAsync(mapper.Map<List<AirportReadModel>>(InitialData.Airports));
}
}
}
private async Task SeedAircraftAsync()
{
if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Aircraft))
{
await flightDbContext.Aircraft.AddRangeAsync(InitialData.Aircrafts);
await flightDbContext.SaveChangesAsync();
if (!await MongoQueryable.AnyAsync(flightReadDbContext.Aircraft.AsQueryable()))
{
await flightReadDbContext.Aircraft.InsertManyAsync(mapper.Map<List<AircraftReadModel>>(InitialData.Aircrafts));
}
}
}
private async Task SeedSeatAsync()
{
if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Seats))
{
await flightDbContext.Seats.AddRangeAsync(InitialData.Seats);
await flightDbContext.SaveChangesAsync();
if (!await MongoQueryable.AnyAsync(flightReadDbContext.Seat.AsQueryable()))
{
await flightReadDbContext.Seat.InsertManyAsync(mapper.Map<List<SeatReadModel>>(InitialData.Seats));
}
}
}
private async Task SeedFlightAsync()
{
if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Flights))
{
await flightDbContext.Flights.AddRangeAsync(InitialData.Flights);
await flightDbContext.SaveChangesAsync();
if (!await MongoQueryable.AnyAsync(flightReadDbContext.Flight.AsQueryable()))
{
await flightReadDbContext.Flight.InsertManyAsync(mapper.Map<List<FlightReadModel>>(InitialData.Flights));
}
}
}
}

View File

@ -0,0 +1,13 @@
namespace EndToEnd.Test.Routes;
public static class ApiRoutes
{
private const string BaseApiPath = "api/v1.0";
public static class Flight
{
public const string Id = "{id}";
public const string GetFlightById = $"{BaseApiPath}/flight/{Id}";
public const string CreateFlight = $"{BaseApiPath}/flight";
}
}

View File

@ -0,0 +1,4 @@
{
"parallelizeAssembly": false,
"parallelizeTestCollections": false
}

View File

@ -109,6 +109,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unit.Test", "2-modular-mono
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "2-modular-monolith-architecture-style\src\Modules\Flight\tests\Integration.Test\Integration.Test.csproj", "{AE7E4AE8-4A5C-44AE-B1FC-2A04824EE29B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EndToEnd.Test", "2-modular-monolith-architecture-style\src\Modules\Flight\tests\EndToEnd.Test\EndToEnd.Test.csproj", "{7CBA4E35-64EA-BFB3-0507-B7DE1E60CD54}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -215,6 +217,10 @@ Global
{AE7E4AE8-4A5C-44AE-B1FC-2A04824EE29B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE7E4AE8-4A5C-44AE-B1FC-2A04824EE29B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE7E4AE8-4A5C-44AE-B1FC-2A04824EE29B}.Release|Any CPU.Build.0 = Release|Any CPU
{7CBA4E35-64EA-BFB3-0507-B7DE1E60CD54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7CBA4E35-64EA-BFB3-0507-B7DE1E60CD54}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7CBA4E35-64EA-BFB3-0507-B7DE1E60CD54}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7CBA4E35-64EA-BFB3-0507-B7DE1E60CD54}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -269,6 +275,7 @@ Global
{02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {AD2FB7C1-8641-47E9-B62D-B3A2D74147D8}
{E7B7E65D-DB14-494C-A748-EF90666FB0B1} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{AE7E4AE8-4A5C-44AE-B1FC-2A04824EE29B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{7CBA4E35-64EA-BFB3-0507-B7DE1E60CD54} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BF29DFD4-25EC-44C4-9DA6-E3AC4B292257}