mirror of
https://github.com/alex289/CleanArchitecture.git
synced 2025-06-29 18:21:08 +00:00
Add integration tests
This commit is contained in:
parent
e937e786a7
commit
bbf2ce4ca2
@ -38,8 +38,8 @@ public class UserController : ApiController
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateUserAsync([FromBody] CreateUserViewModel viewModel)
|
||||
{
|
||||
await _userService.CreateUserAsync(viewModel);
|
||||
return Response();
|
||||
var userId = await _userService.CreateUserAsync(viewModel);
|
||||
return Response(userId);
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
|
@ -16,12 +16,10 @@ public sealed class GetAllUsersTestFixture : QueryHandlerBaseFixture
|
||||
{
|
||||
UserRepository = new();
|
||||
|
||||
SetupUserRepositoryGetAllAsync();
|
||||
|
||||
Handler = new(UserRepository.Object);
|
||||
}
|
||||
|
||||
private void SetupUserRepositoryGetAllAsync()
|
||||
public void SetupUserAsync()
|
||||
{
|
||||
var user = new Mock<User>(() =>
|
||||
new User(
|
||||
|
@ -16,12 +16,10 @@ public sealed class GetUserByIdTestFixture : QueryHandlerBaseFixture
|
||||
{
|
||||
UserRepository = new();
|
||||
|
||||
SetupUserRepositoryGetAllAsync();
|
||||
|
||||
Handler = new(UserRepository.Object, Bus.Object);
|
||||
}
|
||||
|
||||
private void SetupUserRepositoryGetAllAsync()
|
||||
public void SetupUserAsync()
|
||||
{
|
||||
var user = new Mock<User>(() =>
|
||||
new User(
|
||||
|
@ -11,6 +11,8 @@ public sealed class GetAllUsersQueryHandlerTests
|
||||
[Fact]
|
||||
public async Task Should_Get_All_Users()
|
||||
{
|
||||
_fixture.SetupUserAsync();
|
||||
|
||||
var result = await _fixture.Handler.Handle(
|
||||
new(),
|
||||
default);
|
||||
@ -21,4 +23,6 @@ public sealed class GetAllUsersQueryHandlerTests
|
||||
result.Should().ContainSingle();
|
||||
result.FirstOrDefault()!.Id.Should().Be(_fixture.ExistingUserId);
|
||||
}
|
||||
|
||||
// Add Test for deleted user
|
||||
}
|
@ -13,6 +13,8 @@ public sealed class GetUserByIdQueryHandlerTests
|
||||
[Fact]
|
||||
public async Task Should_Get_Existing_User()
|
||||
{
|
||||
_fixture.SetupUserAsync();
|
||||
|
||||
var result = await _fixture.Handler.Handle(
|
||||
new(_fixture.ExistingUserId),
|
||||
default);
|
||||
@ -26,6 +28,8 @@ public sealed class GetUserByIdQueryHandlerTests
|
||||
[Fact]
|
||||
public async Task Should_Raise_Notification_For_No_User()
|
||||
{
|
||||
_fixture.SetupUserAsync();
|
||||
|
||||
var request = new GetUserByIdQuery(Guid.NewGuid());
|
||||
var result = await _fixture.Handler.Handle(
|
||||
request,
|
||||
@ -38,4 +42,6 @@ public sealed class GetUserByIdQueryHandlerTests
|
||||
|
||||
result.Should().BeNull();
|
||||
}
|
||||
|
||||
// Add Test for deleted user
|
||||
}
|
@ -9,7 +9,7 @@ public interface IUserService
|
||||
{
|
||||
public Task<UserViewModel?> GetUserByUserIdAsync(Guid userId);
|
||||
public Task<IEnumerable<UserViewModel>> GetAllUsersAsync();
|
||||
public Task CreateUserAsync(CreateUserViewModel user);
|
||||
public Task<Guid> CreateUserAsync(CreateUserViewModel user);
|
||||
public Task UpdateUserAsync(UpdateUserViewModel user);
|
||||
public Task DeleteUserAsync(Guid userId);
|
||||
}
|
@ -24,6 +24,7 @@ public sealed class GetAllUsersQueryHandler :
|
||||
{
|
||||
return await _userRepository
|
||||
.GetAllNoTracking()
|
||||
.Where(x => !x.Deleted)
|
||||
.Select(x => UserViewModel.FromUser(x))
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ public sealed class GetUserByIdQueryHandler :
|
||||
{
|
||||
var user = _userRepository
|
||||
.GetAllNoTracking()
|
||||
.FirstOrDefault(x => x.Id == request.UserId);
|
||||
.FirstOrDefault(x => x.Id == request.UserId && !x.Deleted);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
|
@ -31,13 +31,17 @@ public sealed class UserService : IUserService
|
||||
return await _bus.QueryAsync(new GetAllUsersQuery());
|
||||
}
|
||||
|
||||
public async Task CreateUserAsync(CreateUserViewModel user)
|
||||
public async Task<Guid> CreateUserAsync(CreateUserViewModel user)
|
||||
{
|
||||
var userId = Guid.NewGuid();
|
||||
|
||||
await _bus.SendCommandAsync(new CreateUserCommand(
|
||||
Guid.NewGuid(),
|
||||
userId,
|
||||
user.Email,
|
||||
user.Surname,
|
||||
user.GivenName));
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
public async Task UpdateUserAsync(UpdateUserViewModel user)
|
||||
|
@ -14,8 +14,8 @@ public class User : Entity
|
||||
public User(
|
||||
Guid id,
|
||||
string email,
|
||||
string givenName,
|
||||
string surname) : base(id)
|
||||
string surname,
|
||||
string givenName) : base(id)
|
||||
{
|
||||
Email = email;
|
||||
GivenName = givenName;
|
||||
|
@ -0,0 +1,63 @@
|
||||
using CleanArchitecture.Domain.Notifications;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace CleanArchitecture.Infrastructure.Tests;
|
||||
|
||||
public sealed class DomainNotificationHandlerTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Create_DomainNotificationHandler_Instance()
|
||||
{
|
||||
var domainNotificationHandler = new DomainNotificationHandler();
|
||||
domainNotificationHandler.GetNotifications().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Handle_DomainNotification()
|
||||
{
|
||||
string key = "Key";
|
||||
string value = "Value";
|
||||
string code = "Code";
|
||||
|
||||
var domainNotification = new DomainNotification(key, value, code);
|
||||
var domainNotificationHandler = new DomainNotificationHandler();
|
||||
domainNotificationHandler.Handle(domainNotification);
|
||||
domainNotificationHandler.GetNotifications().Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Handle_DomainNotification_Overload()
|
||||
{
|
||||
string key = "Key";
|
||||
string value = "Value";
|
||||
string code = "Code";
|
||||
|
||||
var domainNotification = new DomainNotification(key, value, code);
|
||||
var domainNotificationHandler = new DomainNotificationHandler();
|
||||
domainNotificationHandler.Handle(domainNotification, default);
|
||||
domainNotificationHandler.GetNotifications().Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DomainNotification_HasNotifications_After_Handling_One()
|
||||
{
|
||||
string key = "Key";
|
||||
string value = "Value";
|
||||
string code = "Code";
|
||||
|
||||
var domainNotification = new DomainNotification(key, value, code);
|
||||
var domainNotificationHandler = new DomainNotificationHandler();
|
||||
domainNotificationHandler.Handle(domainNotification);
|
||||
|
||||
domainNotificationHandler.HasNotifications().Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DomainNotification_HasNotifications_False_Not_Handling_One()
|
||||
{
|
||||
var domainNotificationHandler = new DomainNotificationHandler();
|
||||
|
||||
domainNotificationHandler.HasNotifications().Should().BeFalse();
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
using CleanArchitecture.Domain.Notifications;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace CleanArchitecture.Infrastructure.Tests;
|
||||
|
||||
public sealed class DomainNotificationTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Create_DomainNotification_Instance()
|
||||
{
|
||||
string key = "Key";
|
||||
string value = "Value";
|
||||
string code = "Code";
|
||||
|
||||
var domainNotification = new DomainNotification(
|
||||
key, value, code);
|
||||
|
||||
domainNotification.Key.Should().Be(key);
|
||||
domainNotification.Value.Should().Be(value);
|
||||
domainNotification.Should().NotBe(default(Guid));
|
||||
domainNotification.Code.Should().Be(code);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Create_DomainNotification_Overload_Instance()
|
||||
{
|
||||
string key = "Key";
|
||||
string value = "Value";
|
||||
string code = "Code";
|
||||
|
||||
var domainNotification = new DomainNotification(
|
||||
key, value, code);
|
||||
|
||||
domainNotification.Key.Should().Be(key);
|
||||
domainNotification.Value.Should().Be(value);
|
||||
domainNotification.Code.Should().Be(code);
|
||||
domainNotification.Should().NotBe(default(Guid));
|
||||
}
|
||||
}
|
@ -9,16 +9,31 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2"/>
|
||||
<PackageReference Include="xunit" Version="2.4.2"/>
|
||||
<PackageReference Include="FluentAssertions" Version="6.10.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="Xunit.Priority" Version="1.1.6" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CleanArchitecture.Api\CleanArchitecture.Api.csproj" />
|
||||
<ProjectReference Include="..\CleanArchitecture.Infrastructure\CleanArchitecture.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="UtilityTests\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -0,0 +1,164 @@
|
||||
using System.Net;
|
||||
using CleanArchitecture.Application.ViewModels.Users;
|
||||
using CleanArchitecture.IntegrationTests.Extensions;
|
||||
using CleanArchitecture.IntegrationTests.Fixtures;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using Xunit.Priority;
|
||||
|
||||
namespace CleanArchitecture.IntegrationTests.Controller;
|
||||
|
||||
[Collection("Integrationtests")]
|
||||
[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)]
|
||||
public sealed class UserControllerTests : IClassFixture<UserTestFixture>
|
||||
{
|
||||
private readonly UserTestFixture _fixture;
|
||||
|
||||
public UserControllerTests(UserTestFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
[Fact, Priority(0)]
|
||||
public async Task Should_Get_No_User()
|
||||
{
|
||||
var response = await _fixture.ServerClient.GetAsync("user");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var message = await response.Content.ReadAsJsonAsync<IEnumerable<UserViewModel>>();
|
||||
|
||||
message?.Data.Should().NotBeNull();
|
||||
|
||||
var content = message!.Data!;
|
||||
|
||||
content.Should().BeNullOrEmpty();
|
||||
}
|
||||
|
||||
[Fact, Priority(5)]
|
||||
public async Task Should_Create_User()
|
||||
{
|
||||
var user = new CreateUserViewModel("test@email.com", "Test", "Email");
|
||||
|
||||
var response = await _fixture.ServerClient.PostAsJsonAsync("user", user);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var message = await response.Content.ReadAsJsonAsync<Guid>();
|
||||
|
||||
message?.Data.Should().NotBeEmpty();
|
||||
|
||||
_fixture.CreatedUserId = message!.Data;
|
||||
}
|
||||
|
||||
[Fact, Priority(10)]
|
||||
public async Task Should_Get_Created_Users()
|
||||
{
|
||||
var response = await _fixture.ServerClient.GetAsync("user/" + _fixture.CreatedUserId);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var message = await response.Content.ReadAsJsonAsync<UserViewModel>();
|
||||
|
||||
message?.Data.Should().NotBeNull();
|
||||
|
||||
var content = message!.Data!;
|
||||
|
||||
content.Id.Should().Be(_fixture.CreatedUserId);
|
||||
content.Email.Should().Be("test@email.com");
|
||||
content.Surname.Should().Be("Test");
|
||||
content.GivenName.Should().Be("Email");
|
||||
}
|
||||
|
||||
[Fact, Priority(15)]
|
||||
public async Task Should_Update_User()
|
||||
{
|
||||
var user = new UpdateUserViewModel(
|
||||
_fixture.CreatedUserId,
|
||||
"newtest@email.com",
|
||||
"NewTest",
|
||||
"NewEmail");
|
||||
|
||||
var response = await _fixture.ServerClient.PutAsJsonAsync("user", user);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var message = await response.Content.ReadAsJsonAsync<UpdateUserViewModel>();
|
||||
|
||||
message?.Data.Should().NotBeNull();
|
||||
|
||||
var content = message!.Data;
|
||||
|
||||
content.Should().BeEquivalentTo(user);
|
||||
}
|
||||
|
||||
[Fact, Priority(20)]
|
||||
public async Task Should_Get_Updated_Users()
|
||||
{
|
||||
var response = await _fixture.ServerClient.GetAsync("user/" + _fixture.CreatedUserId);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var message = await response.Content.ReadAsJsonAsync<UserViewModel>();
|
||||
|
||||
message?.Data.Should().NotBeNull();
|
||||
|
||||
var content = message!.Data!;
|
||||
|
||||
content.Id.Should().Be(_fixture.CreatedUserId);
|
||||
content.Email.Should().Be("newtest@email.com");
|
||||
content.Surname.Should().Be("NewTest");
|
||||
content.GivenName.Should().Be("NewEmail");
|
||||
}
|
||||
|
||||
[Fact, Priority(25)]
|
||||
public async Task Should_Get_One_User()
|
||||
{
|
||||
var response = await _fixture.ServerClient.GetAsync("user");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var message = await response.Content.ReadAsJsonAsync<IEnumerable<UserViewModel>>();
|
||||
|
||||
message?.Data.Should().NotBeNull();
|
||||
|
||||
var content = message!.Data!;
|
||||
|
||||
content.Should().ContainSingle();
|
||||
content.First().Id.Should().Be(_fixture.CreatedUserId);
|
||||
content.First().Email.Should().Be("newtest@email.com");
|
||||
content.First().Surname.Should().Be("NewTest");
|
||||
content.First().GivenName.Should().Be("NewEmail");
|
||||
}
|
||||
|
||||
[Fact, Priority(30)]
|
||||
public async Task Should_Delete_User()
|
||||
{
|
||||
var response = await _fixture.ServerClient.DeleteAsync("user/" + _fixture.CreatedUserId);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var message = await response.Content.ReadAsJsonAsync<Guid>();
|
||||
|
||||
message?.Data.Should().NotBeEmpty();
|
||||
|
||||
var content = message!.Data!;
|
||||
content.Should().Be(_fixture.CreatedUserId);
|
||||
}
|
||||
|
||||
[Fact, Priority(35)]
|
||||
public async Task Should_Get_No_User_Again()
|
||||
{
|
||||
var response = await _fixture.ServerClient.GetAsync("user");
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var message = await response.Content.ReadAsJsonAsync<IEnumerable<UserViewModel>>();
|
||||
|
||||
message?.Data.Should().NotBeNull();
|
||||
|
||||
var content = message!.Data!;
|
||||
|
||||
content.Should().BeNullOrEmpty();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
using System.Data.Common;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
|
||||
namespace CleanArchitecture.IntegrationTests.Extensions;
|
||||
|
||||
public static class FunctionalTestsServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection SetupTestDatabase<TContext>(this IServiceCollection services, DbConnection connection) where TContext : DbContext
|
||||
{
|
||||
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<TContext>));
|
||||
if (descriptor != null)
|
||||
services.Remove(descriptor);
|
||||
|
||||
services.AddScoped(p =>
|
||||
DbContextOptionsFactory<TContext>(
|
||||
p,
|
||||
(sp, options) => options
|
||||
.ConfigureWarnings(b => b.Log(CoreEventId.ManyServiceProvidersCreatedWarning))
|
||||
.UseLazyLoadingProxies()
|
||||
.UseSqlite(connection)));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static DbContextOptions<TContext> DbContextOptionsFactory<TContext>(
|
||||
IServiceProvider applicationServiceProvider,
|
||||
Action<IServiceProvider, DbContextOptionsBuilder> optionsAction)
|
||||
where TContext : DbContext
|
||||
{
|
||||
var builder = new DbContextOptionsBuilder<TContext>(
|
||||
new DbContextOptions<TContext>(new Dictionary<Type, IDbContextOptionsExtension>()));
|
||||
|
||||
builder.UseApplicationServiceProvider(applicationServiceProvider);
|
||||
|
||||
optionsAction?.Invoke(applicationServiceProvider, builder);
|
||||
|
||||
return builder.Options;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using CleanArchitecture.Api.Models;
|
||||
|
||||
namespace CleanArchitecture.IntegrationTests.Extensions;
|
||||
|
||||
public static class HttpExensions
|
||||
{
|
||||
public static JsonSerializerOptions JsonSerializerOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
};
|
||||
|
||||
private static T? Deserialize<T>(string json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return JsonSerializer.Deserialize<T>(json, JsonSerializerOptions);
|
||||
}
|
||||
|
||||
private static string Serialize<T>(T data)
|
||||
{
|
||||
return JsonSerializer.Serialize(data, JsonSerializerOptions);
|
||||
}
|
||||
|
||||
public static async Task<ResponseMessage<T>?> ReadAsJsonAsync<T>(this HttpContent httpContent)
|
||||
{
|
||||
var stringContent = await httpContent.ReadAsStringAsync();
|
||||
|
||||
return Deserialize<ResponseMessage<T>>(stringContent);
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> PatchAsJsonAsync<T>(this HttpClient httpClient, string url, T data)
|
||||
{
|
||||
var content = new StringContent(Serialize(data), Encoding.UTF8, "application/json");
|
||||
|
||||
return httpClient.PatchAsync(url, content);
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<T>(this HttpClient httpClient, string url, T data)
|
||||
{
|
||||
var content = new StringContent(Serialize(data), Encoding.UTF8, "application/json");
|
||||
|
||||
return httpClient.PostAsync(url, content);
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> PutAsJsonAsync<T>(this HttpClient httpClient, string url, T data)
|
||||
{
|
||||
var content = new StringContent(Serialize(data), Encoding.UTF8, "application/json");
|
||||
|
||||
return httpClient.PutAsync(url, content);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
using CleanArchitecture.Infrastructure.Database;
|
||||
using CleanArchitecture.IntegrationTests.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace CleanArchitecture.IntegrationTests.Fixtures;
|
||||
|
||||
public class TestFixtureBase
|
||||
{
|
||||
public HttpClient ServerClient { get; }
|
||||
|
||||
public TestFixtureBase()
|
||||
{
|
||||
var projectDir = Directory.GetCurrentDirectory();
|
||||
var configPath = Path.Combine(projectDir, "appsettings.Integration.json");
|
||||
|
||||
var factory = new CleanArchitectureWebApplicationFactory(
|
||||
SeedTestData,
|
||||
RegisterCustomServicesHandler,
|
||||
configPath);
|
||||
|
||||
ServerClient = factory.CreateClient();
|
||||
ServerClient.Timeout = TimeSpan.FromMinutes(5);
|
||||
}
|
||||
|
||||
protected virtual void SeedTestData(ApplicationDbContext context)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void RegisterCustomServicesHandler(
|
||||
IServiceCollection services,
|
||||
ServiceProvider serviceProvider,
|
||||
IServiceProvider scopedServices)
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace CleanArchitecture.IntegrationTests.Fixtures;
|
||||
|
||||
public sealed class UserTestFixture : TestFixtureBase
|
||||
{
|
||||
public Guid CreatedUserId { get; set; }
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
using CleanArchitecture.Infrastructure.Database;
|
||||
using CleanArchitecture.Infrastructure.Extensions;
|
||||
using CleanArchitecture.IntegrationTests.Extensions;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace CleanArchitecture.IntegrationTests.Infrastructure;
|
||||
|
||||
public sealed class CleanArchitectureWebApplicationFactory : WebApplicationFactory<Program>
|
||||
{
|
||||
public delegate void AddCustomSeedDataHandler(ApplicationDbContext context);
|
||||
|
||||
public delegate void RegisterCustomServicesHandler(
|
||||
IServiceCollection services,
|
||||
ServiceProvider serviceProvider,
|
||||
IServiceProvider scopedServices);
|
||||
|
||||
private readonly SqliteConnection _connection = new($"DataSource=:memory:");
|
||||
|
||||
private readonly AddCustomSeedDataHandler? _addCustomSeedDataHandler;
|
||||
private readonly RegisterCustomServicesHandler? _registerCustomServicesHandler;
|
||||
private readonly string? _environment;
|
||||
|
||||
public CleanArchitectureWebApplicationFactory(
|
||||
AddCustomSeedDataHandler? addCustomSeedDataHandler,
|
||||
RegisterCustomServicesHandler? registerCustomServicesHandler,
|
||||
string? environment = null)
|
||||
{
|
||||
_addCustomSeedDataHandler = addCustomSeedDataHandler;
|
||||
_registerCustomServicesHandler = registerCustomServicesHandler;
|
||||
_environment = environment;
|
||||
}
|
||||
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_environment))
|
||||
{
|
||||
builder.UseEnvironment(_environment);
|
||||
}
|
||||
|
||||
base.ConfigureWebHost(builder);
|
||||
|
||||
_connection.Open();
|
||||
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
services.SetupTestDatabase<ApplicationDbContext>(_connection);
|
||||
|
||||
var sp = services.BuildServiceProvider();
|
||||
|
||||
using IServiceScope scope = sp.CreateScope();
|
||||
var scopedServices = scope.ServiceProvider;
|
||||
|
||||
var applicationDbContext = scopedServices.GetRequiredService<ApplicationDbContext>();
|
||||
|
||||
applicationDbContext.EnsureMigrationsApplied();
|
||||
|
||||
_addCustomSeedDataHandler?.Invoke(applicationDbContext);
|
||||
_registerCustomServicesHandler?.Invoke(services, sp, scopedServices);
|
||||
});
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace CleanArchitecture.IntegrationTests;
|
||||
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
global using Xunit;
|
Loading…
Reference in New Issue
Block a user