add integration test for identity

This commit is contained in:
meysamhadeli 2022-05-23 01:31:11 +04:30
parent b779e6b11a
commit 0573d68f32
28 changed files with 938 additions and 263 deletions

View File

@ -55,7 +55,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Passenger", "src\Services\P
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Passenger.Api", "src\Services\Passenger\src\Passenger.Api\Passenger.Api.csproj", "{4F29C4B6-A7DA-4A92-9CDB-42FE98238837}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Flight\tests\Integration.Test.csproj", "{92E4D21C-2904-46F5-947D-74138003B19F}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Flight\tests\IntegrationTest\Integration.Test.csproj", "{6B6603C8-D8B6-4775-9C7A-FFE6058070C2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Identity\tests\IntegrationTest\Integration.Test.csproj", "{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "src\Services\Passenger\tests\IntegrationTest\Integration.Test.csproj", "{539364C8-88B1-48A3-8406-D0B19FF30509}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -89,7 +93,9 @@ Global
{BEE7A9D7-1BFC-477E-B070-4BE63C0361AA} = {F39D8F09-6233-4495-ACD0-F98904993B7E}
{6D7BCECE-D77D-4C57-A296-CA6E728E94B7} = {85DA00E5-CC11-463C-8577-C34967C328F7}
{4F29C4B6-A7DA-4A92-9CDB-42FE98238837} = {85DA00E5-CC11-463C-8577-C34967C328F7}
{92E4D21C-2904-46F5-947D-74138003B19F} = {C6EE337B-91EA-472A-87C7-E9528408CE59}
{6B6603C8-D8B6-4775-9C7A-FFE6058070C2} = {C6EE337B-91EA-472A-87C7-E9528408CE59}
{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2} = {295284BA-D4E4-40AA-A2C2-BE36343F7DE6}
{539364C8-88B1-48A3-8406-D0B19FF30509} = {C1EBE17D-BFAD-47DA-88EB-BB073B84593E}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A2D7C5C4-5148-4C3E-BB12-B7A197A290F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@ -132,9 +138,17 @@ Global
{4F29C4B6-A7DA-4A92-9CDB-42FE98238837}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F29C4B6-A7DA-4A92-9CDB-42FE98238837}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F29C4B6-A7DA-4A92-9CDB-42FE98238837}.Release|Any CPU.Build.0 = Release|Any CPU
{92E4D21C-2904-46F5-947D-74138003B19F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{92E4D21C-2904-46F5-947D-74138003B19F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{92E4D21C-2904-46F5-947D-74138003B19F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{92E4D21C-2904-46F5-947D-74138003B19F}.Release|Any CPU.Build.0 = Release|Any CPU
{6B6603C8-D8B6-4775-9C7A-FFE6058070C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B6603C8-D8B6-4775-9C7A-FFE6058070C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B6603C8-D8B6-4775-9C7A-FFE6058070C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B6603C8-D8B6-4775-9C7A-FFE6058070C2}.Release|Any CPU.Build.0 = Release|Any CPU
{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC7871B8-BB18-4BCC-96A8-7324C11BF4A2}.Release|Any CPU.Build.0 = Release|Any CPU
{539364C8-88B1-48A3-8406-D0B19FF30509}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{539364C8-88B1-48A3-8406-D0B19FF30509}.Debug|Any CPU.Build.0 = Debug|Any CPU
{539364C8-88B1-48A3-8406-D0B19FF30509}.Release|Any CPU.ActiveCfg = Release|Any CPU
{539364C8-88B1-48A3-8406-D0B19FF30509}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -7,120 +7,126 @@
<ItemGroup>
<PackageReference Include="Ardalis.GuardClauses" Version="3.3.0" />
<PackageReference Include="AspNetCore.HealthChecks.UI.SQLite.Storage" Version="5.0.1" />
<PackageReference Include="Ben.BlockingDetector" Version="0.0.4" />
<PackageReference Include="EasyCaching.Core" Version="1.4.1" />
<PackageReference Include="EasyCaching.InMemory" Version="1.4.1" />
<PackageReference Include="EFCore.NamingConventions" Version="6.0.0" />
<PackageReference Include="EntityFrameworkCore.Triggered" Version="3.0.0" />
<PackageReference Include="Figgle" Version="0.4.0" />
<PackageReference Include="FluentValidation" Version="10.3.6" />
<PackageReference Include="FluentValidation.AspNetCore" Version="10.3.6" />
<PackageReference Include="Grpc.Net.Client" Version="2.44.0" />
<PackageReference Include="MagicOnion" Version="4.4.0" />
<PackageReference Include="MagicOnion.Abstractions" Version="4.4.0" />
<PackageReference Include="MagicOnion.Client" Version="4.4.0" />
<PackageReference Include="MagicOnion.Server" Version="4.4.0" />
<PackageReference Include="MagicOnion.Server" Version="4.4.0" />
<PackageReference Include="MartinCostello.Logging.XUnit" Version="0.2.0" />
<PackageReference Include="NSubstitute" Version="4.3.0" />
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="Ardalis.GuardClauses" Version="3.3.0"/>
<PackageReference Include="AspNetCore.HealthChecks.UI.SQLite.Storage" Version="5.0.1"/>
<PackageReference Include="Ben.BlockingDetector" Version="0.0.4"/>
<PackageReference Include="EasyCaching.Core" Version="1.4.1"/>
<PackageReference Include="EasyCaching.InMemory" Version="1.4.1"/>
<PackageReference Include="EFCore.NamingConventions" Version="6.0.0"/>
<PackageReference Include="EntityFrameworkCore.Triggered" Version="3.0.0"/>
<PackageReference Include="Figgle" Version="0.4.0"/>
<PackageReference Include="FluentValidation" Version="10.3.6"/>
<PackageReference Include="FluentValidation.AspNetCore" Version="10.3.6"/>
<PackageReference Include="Grpc.Net.Client" Version="2.44.0"/>
<PackageReference Include="MagicOnion" Version="4.4.0"/>
<PackageReference Include="MagicOnion.Abstractions" Version="4.4.0"/>
<PackageReference Include="MagicOnion.Client" Version="4.4.0"/>
<PackageReference Include="MagicOnion.Server" Version="4.4.0"/>
<PackageReference Include="MagicOnion.Server" Version="4.4.0"/>
<PackageReference Include="NSubstitute" Version="4.3.0"/>
<PackageReference Include="Polly" Version="7.2.3"/>
<PackageReference Include="protobuf-net.BuildTools" Version="3.0.115">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="protobuf-net.Grpc" Version="1.0.152" />
<PackageReference Include="Hellang.Middleware.ProblemDetails" Version="6.3.0" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="IdGen" Version="3.0.0" />
<PackageReference Include="Mapster" Version="7.3.0" />
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.0" />
<PackageReference Include="MediatR" Version="9.0.0" />
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
<PackageReference Include="MongoDB.Driver" Version="2.14.1" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="OpenTelemetry.Contrib.Instrumentation.MassTransit" Version="1.0.0-beta2" />
<PackageReference Include="protobuf-net.Grpc.AspNetCore" Version="1.0.152" />
<PackageReference Include="Scrutor" Version="3.3.0" />
<PackageReference Include="Scrutor.AspNetCore" Version="3.3.0" />
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="Serilog.Enrichers.Span" Version="2.2.0" />
<PackageReference Include="Serilog.Exceptions" Version="8.1.0" />
<PackageReference Include="Serilog.Formatting.Elasticsearch" Version="8.4.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="8.4.1" />
<PackageReference Include="Serilog.Sinks.Seq" Version="5.1.0" />
<PackageReference Include="Serilog.Sinks.SpectreConsole" Version="0.1.1" />
<PackageReference Include="Serilog.Sinks.XUnit" Version="3.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.2.3" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.2.3" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.2.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="AspNetCore.HealthChecks.UI" Version="5.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="6.0.1" />
<PackageReference Include="System.Interactive.Async" Version="5.1.0" />
<PackageReference Include="MassTransit" Version="8.0.0" />
<PackageReference Include="MassTransit.RabbitMQ" Version="8.0.0" />
<PackageReference Include="DotNetCore.CAP" Version="6.0.0" />
<PackageReference Include="DotNetCore.CAP.Dashboard" Version="6.0.0" />
<PackageReference Include="DotNetCore.CAP.MongoDB" Version="6.0.0" />
<PackageReference Include="DotNetCore.CAP.OpenTelemetry" Version="6.0.0" />
<PackageReference Include="DotNetCore.CAP.RabbitMQ" Version="6.0.0" />
<PackageReference Include="DotNetCore.CAP.SqlServer" Version="6.0.0" />
<PackageReference Include="Duende.IdentityServer" Version="6.0.0" />
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="6.0.0" />
<PackageReference Include="Duende.IdentityServer.EntityFramework" Version="6.0.0" />
<PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" Version="6.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0" />
<PackageReference Include="Yarp.ReverseProxy" Version="1.0.0" />
<PackageReference Include="Microsoft.Identity.Web" Version="1.22.3" />
<PackageReference Include="Jaeger" Version="0.3.7" />
<PackageReference Include="OpenTracing" Version="0.12.1" />
<PackageReference Include="prometheus-net" Version="6.0.0" />
<PackageReference Include="prometheus-net.AspNetCore" Version="6.0.0" />
<PackageReference Include="protobuf-net.Grpc" Version="1.0.152"/>
<PackageReference Include="Hellang.Middleware.ProblemDetails" Version="6.3.0"/>
<PackageReference Include="Humanizer.Core" Version="2.14.1"/>
<PackageReference Include="IdGen" Version="3.0.0"/>
<PackageReference Include="Mapster" Version="7.3.0"/>
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.0"/>
<PackageReference Include="MediatR" Version="9.0.0"/>
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0"/>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0"/>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.0.0"/>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.1"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.1"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1"/>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0"/>
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.0.1"/>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0"/>
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0"/>
<PackageReference Include="MongoDB.Driver" Version="2.14.1"/>
<PackageReference Include="Moq" Version="4.16.1"/>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
<PackageReference Include="OpenTelemetry.Contrib.Instrumentation.MassTransit" Version="1.0.0-beta2"/>
<PackageReference Include="protobuf-net.Grpc.AspNetCore" Version="1.0.152"/>
<PackageReference Include="Scrutor" Version="3.3.0"/>
<PackageReference Include="Scrutor.AspNetCore" Version="3.3.0"/>
<PackageReference Include="Serilog" Version="2.10.0"/>
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0"/>
<PackageReference Include="Serilog.Enrichers.Span" Version="2.2.0"/>
<PackageReference Include="Serilog.Exceptions" Version="8.1.0"/>
<PackageReference Include="Serilog.Formatting.Elasticsearch" Version="8.4.1"/>
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1"/>
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="8.4.1"/>
<PackageReference Include="Serilog.Sinks.Seq" Version="5.1.0"/>
<PackageReference Include="Serilog.Sinks.SpectreConsole" Version="0.1.1"/>
<PackageReference Include="Serilog.Sinks.XUnit" Version="3.0.3"/>
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.2.3"/>
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.2.3"/>
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.2.3"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3"/>
<PackageReference Include="AspNetCore.HealthChecks.UI" Version="5.0.1"/>
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1"/>
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="5.0.1"/>
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.1"/>
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="6.0.1"/>
<PackageReference Include="System.Interactive.Async" Version="5.1.0"/>
<PackageReference Include="MassTransit" Version="8.0.0"/>
<PackageReference Include="MassTransit.RabbitMQ" Version="8.0.0"/>
<PackageReference Include="DotNetCore.CAP" Version="6.0.0"/>
<PackageReference Include="DotNetCore.CAP.Dashboard" Version="6.0.0"/>
<PackageReference Include="DotNetCore.CAP.MongoDB" Version="6.0.0"/>
<PackageReference Include="DotNetCore.CAP.OpenTelemetry" Version="6.0.0"/>
<PackageReference Include="DotNetCore.CAP.RabbitMQ" Version="6.0.0"/>
<PackageReference Include="DotNetCore.CAP.SqlServer" Version="6.0.0"/>
<PackageReference Include="Duende.IdentityServer" Version="6.0.0"/>
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="6.0.0"/>
<PackageReference Include="Duende.IdentityServer.EntityFramework" Version="6.0.0"/>
<PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" Version="6.0.3"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1"/>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0"/>
<PackageReference Include="Yarp.ReverseProxy" Version="1.0.0"/>
<PackageReference Include="Microsoft.Identity.Web" Version="1.22.3"/>
<PackageReference Include="OpenTelemetry" Version="1.2.0-rc3" />
<PackageReference Include="OpenTelemetry.Exporter.Jaeger" Version="1.2.0-rc3" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.0.0-rc9" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc9" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc9" />
<PackageReference Include="Jaeger" Version="0.3.7"/>
<PackageReference Include="OpenTracing" Version="0.12.1"/>
<PackageReference Include="prometheus-net" Version="6.0.0"/>
<PackageReference Include="prometheus-net.AspNetCore" Version="6.0.0"/>
<PackageReference Include="OpenTelemetry" Version="1.2.0-rc3"/>
<PackageReference Include="OpenTelemetry.Exporter.Jaeger" Version="1.2.0-rc3"/>
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.0.0-rc9"/>
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc9"/>
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc9"/>
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.0.64">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="EventStore.Client.Grpc.Streams" Version="22.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.3" />
<PackageReference Include="EventStore.Client.Grpc.Streams" Version="22.0.0"/>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1"/>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.3"/>
<PackageReference Include="Nito.AsyncEx" Version="5.1.2"/>
<PackageReference Include="AutoBogus" Version="2.13.1"/>
<PackageReference Include="Bogus" Version="34.0.1"/>
<PackageReference Include="FluentAssertions" Version="6.2.0"/>
<PackageReference Include="MediatR" Version="9.0.0"/>
<PackageReference Include="Respawn" Version="4.0.0"/>
</ItemGroup>
<ItemGroup>
<Folder Include="Contracts" />
<Folder Include="EventStoreDB\BackgroundWorkers" />
<Folder Include="Contracts"/>
<Folder Include="EventStoreDB\BackgroundWorkers"/>
</ItemGroup>
</Project>

View File

@ -1,34 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
<PackageReference Include="AutoBogus" Version="2.13.1" />
<PackageReference Include="Bogus" Version="34.0.1" />
<PackageReference Include="Docker.DotNet" Version="3.125.5" />
<PackageReference Include="Ductus.FluentDocker" Version="2.10.41" />
<PackageReference Include="FluentAssertions" Version="6.2.0" />
<PackageReference Include="MediatR" Version="9.0.0" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="Respawn" Version="4.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\src\Flight.Api\Flight.Api.csproj" />
</ItemGroup>
</Project>

View File

@ -2,18 +2,22 @@
using BuildingBlocks.Contracts.EventBus.Messages;
using FluentAssertions;
using Integration.Test.Fakes;
using MassTransit;
using MassTransit.Testing;
using Xunit;
namespace Integration.Test.Aircraft;
namespace Integration.Test.Aircraft.Features;
[Collection(nameof(TestFixture))]
public class CreateAircraftTests
{
private readonly TestFixture _fixture;
private readonly ITestHarness _testHarness;
public CreateAircraftTests(TestFixture fixture)
{
_fixture = fixture;
_testHarness = fixture.TestHarness;
}
[Fact]
@ -23,12 +27,12 @@ public class CreateAircraftTests
var command = new FakeCreateAircraftCommand().Generate();
// Act
var aircraftResponse = await _fixture.SendAsync(command);
var response = await _fixture.SendAsync(command);
// Assert
aircraftResponse.Should().NotBeNull();
aircraftResponse?.Name.Should().Be(command.Name);
(await _fixture.IsFaultyPublished<AircraftCreated>()).Should().BeFalse();
(await _fixture.IsPublished<AircraftCreated>()).Should().BeTrue();
response?.Should().NotBeNull();
response?.Name.Should().Be(command.Name);
(await _testHarness.Published.Any<Fault<AircraftCreated>>()).Should().BeFalse();
(await _testHarness.Published.Any<AircraftCreated>()).Should().BeTrue();
}
}

View File

@ -2,18 +2,22 @@
using BuildingBlocks.Contracts.EventBus.Messages;
using FluentAssertions;
using Integration.Test.Fakes;
using MassTransit;
using MassTransit.Testing;
using Xunit;
namespace Integration.Test.Airport;
namespace Integration.Test.Airport.Features;
[Collection(nameof(TestFixture))]
public class CreateAirportTests
{
private readonly TestFixture _fixture;
private readonly ITestHarness _testHarness;
public CreateAirportTests(TestFixture fixture)
{
_fixture = fixture;
_testHarness = fixture.TestHarness;
}
[Fact]
@ -23,12 +27,12 @@ public class CreateAirportTests
var command = new FakeCreateAirportCommand().Generate();
// Act
var airportResponse = await _fixture.SendAsync(command);
var response = await _fixture.SendAsync(command);
// Assert
airportResponse.Should().NotBeNull();
airportResponse?.Name.Should().Be(command.Name);
(await _fixture.IsFaultyPublished<AirportCreated>()).Should().BeFalse();
(await _fixture.IsPublished<AirportCreated>()).Should().BeTrue();
response?.Should().NotBeNull();
response?.Name.Should().Be(command.Name);
(await _testHarness.Published.Any<Fault<AirportCreated>>()).Should().BeFalse();
(await _testHarness.Published.Any<AirportCreated>()).Should().BeTrue();
}
}

View File

@ -2,18 +2,22 @@
using BuildingBlocks.Contracts.EventBus.Messages;
using FluentAssertions;
using Integration.Test.Fakes;
using MassTransit;
using MassTransit.Testing;
using Xunit;
namespace Integration.Test.Flight;
namespace Integration.Test.Flight.Features;
[Collection(nameof(TestFixture))]
public class CreateFlightTests
{
private readonly TestFixture _fixture;
private readonly ITestHarness _testHarness;
public CreateFlightTests(TestFixture fixture)
{
_fixture = fixture;
_testHarness = _fixture.TestHarness;
}
[Fact]
@ -23,12 +27,12 @@ public class CreateFlightTests
var command = new FakeCreateFlightCommand().Generate();
// Act
var flightResponse = await _fixture.SendAsync(command);
var response = await _fixture.SendAsync(command);
// Assert
flightResponse.Should().NotBeNull();
flightResponse?.FlightNumber.Should().Be(command.FlightNumber);
(await _fixture.IsFaultyPublished<FlightCreated>()).Should().BeFalse();
(await _fixture.IsPublished<FlightCreated>()).Should().BeTrue();
response.Should().NotBeNull();
response?.FlightNumber.Should().Be(command.FlightNumber);
(await _testHarness.Published.Any<Fault<FlightCreated>>()).Should().BeFalse();
(await _testHarness.Published.Any<FlightCreated>()).Should().BeTrue();
}
}

View File

@ -1,23 +1,26 @@
using System.Linq;
using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages;
using Flight.Flights.Features.CreateFlight;
using Flight.Flights.Features.DeleteFlight;
using FluentAssertions;
using Integration.Test.Fakes;
using MassTransit;
using MassTransit.Testing;
using Microsoft.EntityFrameworkCore;
using Xunit;
namespace Integration.Test.Flight;
namespace Integration.Test.Flight.Features;
[Collection(nameof(TestFixture))]
public class DeleteFlightTests
{
private readonly TestFixture _fixture;
private readonly ITestHarness _testHarness;
public DeleteFlightTests(TestFixture fixture)
{
_fixture = fixture;
_testHarness = fixture.TestHarness;
}
[Fact]
@ -43,8 +46,8 @@ public class DeleteFlightTests
// Assert
deletedFlight?.IsDeleted.Should().BeTrue();
(await _fixture.IsFaultyPublished<FlightDeleted>()).Should().BeFalse();
(await _fixture.IsPublished<FlightDeleted>()).Should().BeTrue();
(await _testHarness.Published.Any<Fault<FlightDeleted>>()).Should().BeFalse();
(await _testHarness.Published.Any<FlightDeleted>()).Should().BeTrue();
}
}

View File

@ -1,16 +1,11 @@
using System.Linq;
using System.Threading.Tasks;
using AutoBogus;
using Bogus;
using BuildingBlocks.IdsGenerator;
using Flight.Flights.Features.CreateFlight;
using Flight.Flights.Features.GetAvailableFlights;
using Flight.Flights.Features.GetFlightById;
using FluentAssertions;
using Integration.Test.Fakes;
using Xunit;
namespace Integration.Test.Flight;
namespace Integration.Test.Flight.Features;
[Collection(nameof(TestFixture))]
public class GetAvailableFlightsTests
@ -42,10 +37,10 @@ public class GetAvailableFlightsTests
var query = new GetAvailableFlightsQuery();
// Act
var flightResponse = await _fixture.SendAsync(query);
var response = (await _fixture.SendAsync(query))?.ToList();
// Assert
flightResponse?.Should().NotBeNull();
flightResponse?.Count().Should().BeGreaterOrEqualTo(2);
response?.Should().NotBeNull();
response?.Count().Should().BeGreaterOrEqualTo(2);
}
}

View File

@ -1,12 +1,10 @@
using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages;
using Flight.Flights.Features.CreateFlight;
using Flight.Flights.Features.GetFlightById;
using FluentAssertions;
using Integration.Test.Fakes;
using Xunit;
namespace Integration.Test.Flight;
namespace Integration.Test.Flight.Features;
[Collection(nameof(TestFixture))]
public class GetFlightByIdTests
@ -31,10 +29,10 @@ public class GetFlightByIdTests
var query = new GetFlightByIdQuery(flightEntity.Id);
// Act
var flightResponse = await _fixture.SendAsync(query);
var response = await _fixture.SendAsync(query);
// Assert
flightResponse.Should().NotBeNull();
flightResponse?.Id.Should().Be(flightEntity.Id);
response.Should().NotBeNull();
response?.Id.Should().Be(flightEntity.Id);
}
}

View File

@ -1,22 +1,23 @@
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages;
using Flight.Flights.Features.CreateFlight;
using FluentAssertions;
using Integration.Test.Fakes;
using Microsoft.EntityFrameworkCore;
using MassTransit;
using MassTransit.Testing;
using Xunit;
namespace Integration.Test.Flight;
namespace Integration.Test.Flight.Features;
[Collection(nameof(TestFixture))]
public class UpdateFlightTests
{
private readonly TestFixture _fixture;
private readonly ITestHarness _testHarness;
public UpdateFlightTests(TestFixture fixture)
{
_fixture = fixture;
_testHarness = _fixture.TestHarness;
}
[Fact]
@ -33,13 +34,13 @@ public class UpdateFlightTests
var command = new FakeUpdateFlightCommand(flightEntity.Id).Generate();
// Act
var flightResponse = await _fixture.SendAsync(command);
var response = await _fixture.SendAsync(command);
// Assert
flightResponse.Should().NotBeNull();
flightResponse?.Id.Should().Be(flightEntity?.Id);
flightResponse?.Price.Should().NotBe(flightEntity?.Price);
(await _fixture.IsFaultyPublished<FlightUpdated>()).Should().BeFalse();
(await _fixture.IsPublished<FlightUpdated>()).Should().BeTrue();
response.Should().NotBeNull();
response?.Id.Should().Be(flightEntity?.Id);
response?.Price.Should().NotBe(flightEntity?.Price);
(await _testHarness.Published.Any<Fault<FlightUpdated>>()).Should().BeFalse();
(await _testHarness.Published.Any<FlightUpdated>()).Should().BeTrue();
}
}

View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.4"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
<PackageReference Include="xunit" Version="2.4.1"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</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>

View File

@ -17,6 +17,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.VisualStudio.TestPlatform.TestHost;
using NSubstitute;
using Respawn;
using Serilog;
@ -33,14 +34,18 @@ public class TestFixtureCollection : ICollectionFixture<TestFixture>
// ref: https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0
// ref: https://github.com/jbogard/ContosoUniversityDotNetCore-Pages/blob/master/ContosoUniversity.IntegrationTests/SliceFixture.cs
// ref: https://github.com/jasontaylordev/CleanArchitecture/blob/main/tests/Application.IntegrationTests/Testing.cs
// ref: https://github.com/MassTransit/MassTransit/blob/00d6992286911a437b63b93c89a56e920b053c11/src/MassTransit.TestFramework/InMemoryTestFixture.cs
public class TestFixture : IAsyncLifetime
{
private Checkpoint _checkpoint;
private IConfiguration _configuration;
private WebApplicationFactory<Program> _factory;
private ITestHarness _harness;
private IServiceScopeFactory _scopeFactory;
private HttpClient _httpClient;
private ITestHarness _testHarness;
public ITestHarness TestHarness => _testHarness;
public async Task InitializeAsync()
{
@ -69,9 +74,9 @@ public class TestFixture : IAsyncLifetime
});
}));
_harness = _factory.Services.GetTestHarness();
_testHarness = _factory.Services.GetTestHarness();
await _harness.Start();
await _testHarness.Start();
_configuration = _factory.Services.GetRequiredService<IConfiguration>();
_scopeFactory = _factory.Services.GetRequiredService<IServiceScopeFactory>();
@ -85,7 +90,7 @@ public class TestFixture : IAsyncLifetime
public async Task DisposeAsync()
{
_harness.Cancel();
_testHarness.Cancel();
await _factory.DisposeAsync();
await _checkpoint.Reset(_configuration.GetConnectionString("DefaultConnection"));
}
@ -242,69 +247,6 @@ public class TestFixture : IAsyncLifetime
});
}
// ref: https://github.com/MassTransit/MassTransit/blob/00d6992286911a437b63b93c89a56e920b053c11/src/MassTransit.TestFramework/InMemoryTestFixture.cs
// ref: https://wrapt.dev/blog/building-an-event-driven-dotnet-application-integration-testing
/// <summary>
/// Publishes a message to the bus, and waits for the specified response.
/// </summary>
/// <param name="message">The message that should be published.</param>
/// <typeparam name="TMessage">The message that should be published.</typeparam>
public async Task PublishMessage<TMessage>(object message)
where TMessage : class
{
await _harness.Bus.Publish<TMessage>(message);
}
/// <summary>
/// Confirm if there was a fault when publishing for this harness.
/// </summary>
/// <typeparam name="TMessage">The message that should be published.</typeparam>
/// <returns>A boolean of true if there was a fault for a message of the given type when published.</returns>
public Task<bool> IsFaultyPublished<TMessage>()
where TMessage : class
{
return _harness.Published.Any<Fault<TMessage>>();
}
/// <summary>
/// Confirm that a message has been published for this harness.
/// </summary>
/// <typeparam name="TMessage">The message that should be published.</typeparam>
/// <returns>A boolean of true if a message of the given type has been published.</returns>
public Task<bool> IsPublished<TMessage>()
where TMessage : class
{
return _harness.Published.Any<TMessage>();
}
/// <summary>
/// Confirm that a message has been consumed for this harness.
/// </summary>
/// <typeparam name="TMessage">The message that should be consumed.</typeparam>
/// <returns>A boolean of true if a message of the given type has been consumed.</returns>
public Task<bool> IsConsumed<TMessage>()
where TMessage : class
{
return _harness.Consumed.Any<TMessage>();
}
/// <summary>
/// The desired consumer consumed the message.
/// </summary>
/// <typeparam name="TMessage">The message that should be consumed.</typeparam>
/// <typeparam name="TConsumedBy">The consumer of the message.</typeparam>
/// <returns>A boolean of true if a message of the given type has been consumed by the given consumer.</returns>
public Task<bool> IsConsumed<TMessage, TConsumedBy>()
where TMessage : class
where TConsumedBy : class, IConsumer
{
using var scope = _scopeFactory.CreateScope();
var consumerHarness = scope.ServiceProvider.GetRequiredService<IConsumerTestHarness<TConsumedBy>>();
return consumerHarness.Consumed.Any<TMessage>();
}
private async Task EnsureDatabaseAsync()
{
using var scope = _scopeFactory.CreateScope();
@ -323,7 +265,7 @@ public class TestFixture : IAsyncLifetime
using var scope = serviceProvider.CreateScope();
httpContextAccessorMock.HttpContext = new DefaultHttpContext {RequestServices = scope.ServiceProvider};
httpContextAccessorMock.HttpContext.Request.Host = new HostString("localhost", 5000);
httpContextAccessorMock.HttpContext.Request.Host = new HostString("localhost", 5004);
httpContextAccessorMock.HttpContext.Request.Scheme = "http";
return httpContextAccessorMock;

View File

@ -79,3 +79,5 @@ app.UseEndpoints(endpoints =>
app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name));
app.Run();
public partial class Program {}

View File

@ -0,0 +1,19 @@
{
"ConnectionStrings": {
"DefaultConnection": "Server=.\\sqlexpress;Database=IdentityDB_Test;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"RabbitMq": {
"HostName": "localhost",
"ExchangeName": "identity",
"UserName": "guest",
"Password": "guest"
},
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Debug",
"Microsoft.EntityFrameworkCore.Database.Command": "Debug"
}
}
}

View File

@ -35,14 +35,14 @@ public class IdentityDataSeeder : IDataSeeder
private async Task SeedUsers()
{
if (await _userManager.FindByNameAsync("meysamh") == null)
if (await _userManager.FindByNameAsync("samh") == null)
{
var user = new ApplicationUser
{
FirstName = "Meysam",
LastName = "Hadeli",
UserName = "meysamh",
Email = "meysam@test.com",
FirstName = "Sam",
LastName = "H",
UserName = "samh",
Email = "sam@test.com",
SecurityStamp = Guid.NewGuid().ToString()
};
@ -56,10 +56,10 @@ public class IdentityDataSeeder : IDataSeeder
{
var user = new ApplicationUser
{
FirstName = "Meysam",
LastName = "Hadeli",
UserName = "meysamh2",
Email = "meysam2@test.com",
FirstName = "Sam",
LastName = "H",
UserName = "samh2",
Email = "sam2@test.com",
SecurityStamp = Guid.NewGuid().ToString()
};

View File

@ -0,0 +1,14 @@
using AutoBogus;
using Identity.Identity.Features.RegisterNewUser;
namespace Integration.Test.Fakes;
public class FakeRegisterNewUserCommand : AutoFaker<RegisterNewUserCommand>
{
public FakeRegisterNewUserCommand()
{
RuleFor(r => r.Password, _ => "Password@123");
RuleFor(r => r.ConfirmPassword, _ => "Password@123");
RuleFor(r => r.Email, _ => "test@test.com");
}
}

View File

@ -0,0 +1,38 @@
using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages;
using FluentAssertions;
using Integration.Test.Fakes;
using MassTransit;
using MassTransit.Testing;
using Xunit;
namespace Integration.Test.Identity.Features;
[Collection(nameof(TestFixture))]
public class RegisterNewUserTests
{
private readonly TestFixture _fixture;
private readonly ITestHarness _testHarness;
public RegisterNewUserTests(TestFixture fixture)
{
_fixture = fixture;
_testHarness = _fixture.TestHarness;
}
[Fact]
public async Task should_create_new_user_to_db_and_publish_message_to_broker()
{
// Arrange
var command = new FakeRegisterNewUserCommand().Generate();
// Act
var response = await _fixture.SendAsync(command);
// Assert
response?.Should().NotBeNull();
response?.Username.Should().Be(command.Username);
(await _testHarness.Published.Any<Fault<UserCreated>>()).Should().BeFalse();
(await _testHarness.Published.Any<UserCreated>()).Should().BeTrue();
}
}

View File

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.4"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
<PackageReference Include="xunit" Version="2.4.1"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</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\Identity.Api\Identity.Api.csproj"/>
</ItemGroup>
</Project>

View File

@ -0,0 +1,271 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using BuildingBlocks.Domain.Model;
using BuildingBlocks.EFCore;
using BuildingBlocks.MassTransit;
using BuildingBlocks.Web;
using Identity.Data;
using MassTransit;
using MassTransit.Testing;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using NSubstitute;
using Respawn;
using Serilog;
using Xunit;
using Xunit.Abstractions;
namespace Integration.Test;
[CollectionDefinition(nameof(TestFixture))]
public class TestFixtureCollection : ICollectionFixture<TestFixture>
{
}
// ref: https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0
// ref: https://github.com/jbogard/ContosoUniversityDotNetCore-Pages/blob/master/ContosoUniversity.IntegrationTests/SliceFixture.cs
// ref: https://github.com/jasontaylordev/CleanArchitecture/blob/main/tests/Application.IntegrationTests/Testing.cs
// ref: https://github.com/MassTransit/MassTransit/blob/00d6992286911a437b63b93c89a56e920b053c11/src/MassTransit.TestFramework/InMemoryTestFixture.cs
public class TestFixture : IAsyncLifetime
{
private Checkpoint _checkpoint;
private IConfiguration _configuration;
private WebApplicationFactory<Program> _factory;
private HttpClient _httpClient;
private IServiceScopeFactory _scopeFactory;
public ITestHarness TestHarness { get; private set; }
public async Task InitializeAsync()
{
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "test");
_factory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder => builder.ConfigureServices(services =>
{
services.RemoveAll(typeof(IHostedService));
services.ReplaceSingleton(AddHttpContextAccessorMock);
services.ReplaceScoped<IDataSeeder, IdentityDataSeeder>();
services.AddMassTransitTestHarness(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
var rabbitMqOptions = services.GetOptions<RabbitMqOptions>("RabbitMq");
var host = rabbitMqOptions.HostName;
cfg.Host(host, h =>
{
h.Username(rabbitMqOptions.UserName);
h.Password(rabbitMqOptions.Password);
});
cfg.ConfigureEndpoints(context);
});
});
}));
TestHarness = _factory.Services.GetTestHarness();
await TestHarness.Start();
_configuration = _factory.Services.GetRequiredService<IConfiguration>();
_scopeFactory = _factory.Services.GetRequiredService<IServiceScopeFactory>();
_httpClient = _factory.CreateClient(new WebApplicationFactoryClientOptions {AllowAutoRedirect = false});
_checkpoint = new Checkpoint {TablesToIgnore = new[] {"__EFMigrationsHistory"}};
await EnsureDatabaseAsync();
}
public async Task DisposeAsync()
{
TestHarness.Cancel();
await _factory.DisposeAsync();
await _checkpoint.Reset(_configuration.GetConnectionString("DefaultConnection"));
}
// ref: https://github.com/trbenning/serilog-sinks-xunit
public ILogger CreateLogger(ITestOutputHelper output)
{
if (output != null)
return new LoggerConfiguration()
.WriteTo.TestOutput(output)
.CreateLogger();
return null;
}
public HttpClient CreateClient()
{
return _httpClient;
}
public async Task ExecuteScopeAsync(Func<IServiceProvider, Task> action)
{
using var scope = _scopeFactory.CreateScope();
await action(scope.ServiceProvider);
}
public async Task<T> ExecuteScopeAsync<T>(Func<IServiceProvider, Task<T>> action)
{
using var scope = _scopeFactory.CreateScope();
var result = await action(scope.ServiceProvider);
return result;
}
public Task ExecuteDbContextAsync(Func<IdentityContext, Task> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<IdentityContext>()));
}
public Task ExecuteDbContextAsync(Func<IdentityContext, ValueTask> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<IdentityContext>()).AsTask());
}
public Task ExecuteDbContextAsync(Func<IdentityContext, IMediator, Task> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<IdentityContext>(), sp.GetService<IMediator>()));
}
public Task<T> ExecuteDbContextAsync<T>(Func<IdentityContext, Task<T>> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<IdentityContext>()));
}
public Task<T> ExecuteDbContextAsync<T>(Func<IdentityContext, ValueTask<T>> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<IdentityContext>()).AsTask());
}
public Task<T> ExecuteDbContextAsync<T>(Func<IdentityContext, IMediator, Task<T>> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<IdentityContext>(), sp.GetService<IMediator>()));
}
public Task InsertAsync<T>(params T[] entities) where T : class
{
return ExecuteDbContextAsync(db =>
{
foreach (var entity in entities) db.Set<T>().Add(entity);
return db.SaveChangesAsync();
});
}
public Task InsertAsync<TEntity>(TEntity entity) where TEntity : class
{
return ExecuteDbContextAsync(db =>
{
db.Set<TEntity>().Add(entity);
return db.SaveChangesAsync();
});
}
public Task InsertAsync<TEntity, TEntity2>(TEntity entity, TEntity2 entity2)
where TEntity : class
where TEntity2 : class
{
return ExecuteDbContextAsync(db =>
{
db.Set<TEntity>().Add(entity);
db.Set<TEntity2>().Add(entity2);
return db.SaveChangesAsync();
});
}
public Task InsertAsync<TEntity, TEntity2, TEntity3>(TEntity entity, TEntity2 entity2, TEntity3 entity3)
where TEntity : class
where TEntity2 : class
where TEntity3 : class
{
return ExecuteDbContextAsync(db =>
{
db.Set<TEntity>().Add(entity);
db.Set<TEntity2>().Add(entity2);
db.Set<TEntity3>().Add(entity3);
return db.SaveChangesAsync();
});
}
public Task InsertAsync<TEntity, TEntity2, TEntity3, TEntity4>(TEntity entity, TEntity2 entity2, TEntity3 entity3,
TEntity4 entity4)
where TEntity : class
where TEntity2 : class
where TEntity3 : class
where TEntity4 : class
{
return ExecuteDbContextAsync(db =>
{
db.Set<TEntity>().Add(entity);
db.Set<TEntity2>().Add(entity2);
db.Set<TEntity3>().Add(entity3);
db.Set<TEntity4>().Add(entity4);
return db.SaveChangesAsync();
});
}
public Task<T> FindAsync<T>(long id)
where T : class, IEntity
{
return ExecuteDbContextAsync(db => db.Set<T>().FindAsync(id).AsTask());
}
public Task<TResponse> SendAsync<TResponse>(IRequest<TResponse> request)
{
return ExecuteScopeAsync(sp =>
{
var mediator = sp.GetRequiredService<IMediator>();
return mediator.Send(request);
});
}
public Task SendAsync(IRequest request)
{
return ExecuteScopeAsync(sp =>
{
var mediator = sp.GetRequiredService<IMediator>();
return mediator.Send(request);
});
}
private async Task EnsureDatabaseAsync()
{
using var scope = _scopeFactory.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<IdentityContext>();
var seeders = scope.ServiceProvider.GetServices<IDataSeeder>();
await context.Database.MigrateAsync();
foreach (var seeder in seeders) await seeder.SeedAllAsync();
}
private IHttpContextAccessor AddHttpContextAccessorMock(IServiceProvider serviceProvider)
{
var httpContextAccessorMock = Substitute.For<IHttpContextAccessor>();
using var scope = serviceProvider.CreateScope();
httpContextAccessorMock.HttpContext = new DefaultHttpContext {RequestServices = scope.ServiceProvider};
httpContextAccessorMock.HttpContext.Request.Host = new HostString("localhost", 6005);
httpContextAccessorMock.HttpContext.Request.Scheme = "http";
return httpContextAccessorMock;
}
}

View File

@ -80,3 +80,5 @@ app.UseEndpoints(endpoints =>
app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name));
app.Run();
public partial class Program {}

View File

@ -0,0 +1,19 @@
{
"ConnectionStrings": {
"DefaultConnection": "Server=.\\sqlexpress;Database=PassengerDB_Test;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"RabbitMq": {
"HostName": "localhost",
"ExchangeName": "passenger",
"UserName": "guest",
"Password": "guest"
},
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Debug",
"Microsoft.EntityFrameworkCore.Database.Command": "Debug"
}
}
}

View File

@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.4"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
<PackageReference Include="xunit" Version="2.4.1"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</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\Passenger.Api\Passenger.Api.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Fakes" />
<Folder Include="Passenger\Features" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,270 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using BuildingBlocks.Domain.Model;
using BuildingBlocks.EFCore;
using BuildingBlocks.MassTransit;
using BuildingBlocks.Web;
using MassTransit;
using MassTransit.Testing;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using NSubstitute;
using Passenger.Data;
using Respawn;
using Serilog;
using Xunit;
using Xunit.Abstractions;
namespace Integration.Test;
[CollectionDefinition(nameof(TestFixture))]
public class TestFixtureCollection : ICollectionFixture<TestFixture>
{
}
// ref: https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0
// ref: https://github.com/jbogard/ContosoUniversityDotNetCore-Pages/blob/master/ContosoUniversity.IntegrationTests/SliceFixture.cs
// ref: https://github.com/jasontaylordev/CleanArchitecture/blob/main/tests/Application.IntegrationTests/Testing.cs
// ref: https://github.com/MassTransit/MassTransit/blob/00d6992286911a437b63b93c89a56e920b053c11/src/MassTransit.TestFramework/InMemoryTestFixture.cs
public class TestFixture : IAsyncLifetime
{
private Checkpoint _checkpoint;
private IConfiguration _configuration;
private WebApplicationFactory<Program> _factory;
private HttpClient _httpClient;
private IServiceScopeFactory _scopeFactory;
public ITestHarness TestHarness { get; private set; }
public async Task InitializeAsync()
{
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "test");
_factory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder => builder.ConfigureServices(services =>
{
services.RemoveAll(typeof(IHostedService));
services.ReplaceSingleton(AddHttpContextAccessorMock);
services.AddMassTransitTestHarness(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
var rabbitMqOptions = services.GetOptions<RabbitMqOptions>("RabbitMq");
var host = rabbitMqOptions.HostName;
cfg.Host(host, h =>
{
h.Username(rabbitMqOptions.UserName);
h.Password(rabbitMqOptions.Password);
});
cfg.ConfigureEndpoints(context);
});
});
}));
TestHarness = _factory.Services.GetTestHarness();
await TestHarness.Start();
_configuration = _factory.Services.GetRequiredService<IConfiguration>();
_scopeFactory = _factory.Services.GetRequiredService<IServiceScopeFactory>();
_httpClient = _factory.CreateClient(new WebApplicationFactoryClientOptions {AllowAutoRedirect = false});
_checkpoint = new Checkpoint {TablesToIgnore = new[] {"__EFMigrationsHistory"}};
await EnsureDatabaseAsync();
}
public async Task DisposeAsync()
{
TestHarness.Cancel();
await _factory.DisposeAsync();
await _checkpoint.Reset(_configuration.GetConnectionString("DefaultConnection"));
}
// ref: https://github.com/trbenning/serilog-sinks-xunit
public ILogger CreateLogger(ITestOutputHelper output)
{
if (output != null)
return new LoggerConfiguration()
.WriteTo.TestOutput(output)
.CreateLogger();
return null;
}
public HttpClient CreateClient()
{
return _httpClient;
}
public async Task ExecuteScopeAsync(Func<IServiceProvider, Task> action)
{
using var scope = _scopeFactory.CreateScope();
await action(scope.ServiceProvider);
}
public async Task<T> ExecuteScopeAsync<T>(Func<IServiceProvider, Task<T>> action)
{
using var scope = _scopeFactory.CreateScope();
var result = await action(scope.ServiceProvider);
return result;
}
public Task ExecuteDbContextAsync(Func<PassengerDbContext, Task> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<PassengerDbContext>()));
}
public Task ExecuteDbContextAsync(Func<PassengerDbContext, ValueTask> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<PassengerDbContext>()).AsTask());
}
public Task ExecuteDbContextAsync(Func<PassengerDbContext, IMediator, Task> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<PassengerDbContext>(), sp.GetService<IMediator>()));
}
public Task<T> ExecuteDbContextAsync<T>(Func<PassengerDbContext, Task<T>> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<PassengerDbContext>()));
}
public Task<T> ExecuteDbContextAsync<T>(Func<PassengerDbContext, ValueTask<T>> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<PassengerDbContext>()).AsTask());
}
public Task<T> ExecuteDbContextAsync<T>(Func<PassengerDbContext, IMediator, Task<T>> action)
{
return ExecuteScopeAsync(sp => action(sp.GetService<PassengerDbContext>(), sp.GetService<IMediator>()));
}
public Task InsertAsync<T>(params T[] entities) where T : class
{
return ExecuteDbContextAsync(db =>
{
foreach (var entity in entities) db.Set<T>().Add(entity);
return db.SaveChangesAsync();
});
}
public Task InsertAsync<TEntity>(TEntity entity) where TEntity : class
{
return ExecuteDbContextAsync(db =>
{
db.Set<TEntity>().Add(entity);
return db.SaveChangesAsync();
});
}
public Task InsertAsync<TEntity, TEntity2>(TEntity entity, TEntity2 entity2)
where TEntity : class
where TEntity2 : class
{
return ExecuteDbContextAsync(db =>
{
db.Set<TEntity>().Add(entity);
db.Set<TEntity2>().Add(entity2);
return db.SaveChangesAsync();
});
}
public Task InsertAsync<TEntity, TEntity2, TEntity3>(TEntity entity, TEntity2 entity2, TEntity3 entity3)
where TEntity : class
where TEntity2 : class
where TEntity3 : class
{
return ExecuteDbContextAsync(db =>
{
db.Set<TEntity>().Add(entity);
db.Set<TEntity2>().Add(entity2);
db.Set<TEntity3>().Add(entity3);
return db.SaveChangesAsync();
});
}
public Task InsertAsync<TEntity, TEntity2, TEntity3, TEntity4>(TEntity entity, TEntity2 entity2, TEntity3 entity3,
TEntity4 entity4)
where TEntity : class
where TEntity2 : class
where TEntity3 : class
where TEntity4 : class
{
return ExecuteDbContextAsync(db =>
{
db.Set<TEntity>().Add(entity);
db.Set<TEntity2>().Add(entity2);
db.Set<TEntity3>().Add(entity3);
db.Set<TEntity4>().Add(entity4);
return db.SaveChangesAsync();
});
}
public Task<T> FindAsync<T>(long id)
where T : class, IEntity
{
return ExecuteDbContextAsync(db => db.Set<T>().FindAsync(id).AsTask());
}
public Task<TResponse> SendAsync<TResponse>(IRequest<TResponse> request)
{
return ExecuteScopeAsync(sp =>
{
var mediator = sp.GetRequiredService<IMediator>();
return mediator.Send(request);
});
}
public Task SendAsync(IRequest request)
{
return ExecuteScopeAsync(sp =>
{
var mediator = sp.GetRequiredService<IMediator>();
return mediator.Send(request);
});
}
private async Task EnsureDatabaseAsync()
{
using var scope = _scopeFactory.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<PassengerDbContext>();
var seeders = scope.ServiceProvider.GetServices<IDataSeeder>();
await context.Database.MigrateAsync();
foreach (var seeder in seeders) await seeder.SeedAllAsync();
}
private IHttpContextAccessor AddHttpContextAccessorMock(IServiceProvider serviceProvider)
{
var httpContextAccessorMock = Substitute.For<IHttpContextAccessor>();
using var scope = serviceProvider.CreateScope();
httpContextAccessorMock.HttpContext = new DefaultHttpContext {RequestServices = scope.ServiceProvider};
httpContextAccessorMock.HttpContext.Request.Host = new HostString("localhost", 6012);
httpContextAccessorMock.HttpContext.Request.Scheme = "http";
return httpContextAccessorMock;
}
}

View File

@ -0,0 +1,12 @@
using Xunit;
namespace Integration.Test;
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}