在集成测试中共享DbContext

问题描述 投票:0回答:1

为了进行集成测试,我使用 TestContainer 包(SQL Server)。我还有一个

BaseWebApplicationTest
类来共享一些属性,例如
HttpClient
AppDbContext

这是我的

WebApplicationFactory
:

public class IntegrationTestWebApplicationFactory<TProgram>
    : WebApplicationFactory<TProgram>, IAsyncLifetime
    where TProgram : class
{
    private readonly MsSqlContainer _msSqlContainer = new MsSqlBuilder()
        .WithImage("mcr.microsoft.com/mssql/server:2022-latest")
        .Build();

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureTestServices(services =>
        {
            services.RemoveAll<DbContextOptions<AppDbContext>>();
            services.AddSqlServer<AppDbContext>(_msSqlContainer.GetConnectionString());
        });
    }

    public Task InitializeAsync() => _msSqlContainer.StartAsync();

    public new Task DisposeAsync() => _msSqlContainer.StopAsync();
}

这是我的抽象类,用于共享我的测试用例中所需的属性:

public abstract class BaseWebApplicationTest
{
    private readonly IServiceScope _scope;
    protected readonly HttpClient _httpClient;
    protected readonly AppDbContext _context;

    protected BaseWebApplicationTest(IntegrationTestWebApplicationFactory<Program> factory)
    {
        _scope = factory.Services.CreateScope();
        _context = _scope.ServiceProvider.GetRequiredService<AppDbContext>();
        _httpClient = factory.CreateClient();
    }
}

这是我的用户测试控制器的示例:

[Collection(nameof(WebApplicationCollectionFixture))]
public class UserControllerTests(IntegrationTestWebApplicationFactory<Program> factory)
    : BaseWebApplicationTest(factory)
{
    [Fact]
    public async Task CreateUser_Should_Return201StatusCode_WhenUserDoesNotExist()
    {
        // Arrange
        var role = new Role()
        {
            Name = "admin",
            Description = "This is admin user",
        };
        await _context.Roles.AddAsync(role);
        await _context.SaveChangesAsync();

        CreateUserRequest request = new(
            "First Name",
            "Last Name",
            "user_name",
            "[email protected]",
            "Password123",
            RoleId: role.Id);

        // Act
        HttpResponseMessage response = await _httpClient.PostAsJsonAsync("/api/user", request);

        // Assertions
        response.EnsureSuccessStatusCode();
        response.StatusCode
            .Should()
            .Be(System.Net.HttpStatusCode.Created);

        Guid userId = await response.Content.ReadFromJsonAsync<Guid>();
        userId.Should().NotBeEmpty();

        var userCreated = await _context.Users.FindAsync(userId);
        
        userCreated.Should().NotBeNull();
        userCreated!.Id.Should().Be(userId);
        userCreated!.Username.Should().Be(request.UserName);
        // check others properties if you want...
    }
}

到目前为止一切都还好。当我尝试更新用户时出现问题。这些更改不会反映在测试环境中。我的意思是,更新用户后,我得到了它,但更改没有反映出来。为什么?

这是测试用例:

[Fact]
public async Task Update_Should_Return200StatusCode_WhenRequestDataIsValid()
{
    // Arrange
    var role = new Role()
    {
        Name = "admin1x",
        Description = "This is admin user"
    };

    var user = new User()
    {
        FirstName = "First Name",
        LastName = "Last Name",
        Email = "[email protected]",
        Password = "Pass123@",
        Username = "user_name3",
        Role = role
    };

    await _context.Roles.AddAsync(role);
    await _context.Users.AddAsync(user);
    await _context.SaveChangesAsync();

    CreateUserRequest request = new(
        "Name changed",
        "Last Name changed",
        "user_changed",
        "[email protected]",
        "PassChanged123$",
        RoleId: role.Id);

    // Act
    HttpResponseMessage response = await _httpClient.PutAsJsonAsync(
        $"/api/user/{user.Id}",
        request);
    
    // Assert
    response.EnsureSuccessStatusCode();
    response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);

    Guid id = await response.Content.ReadFromJsonAsync<Guid>();
    id.Should().NotBeEmpty();
    
    var userChanged = await _context.Users.FindAsync(id); // I get the update user

    userChanged?.FirstName.Should().Be(request.FirstName);
    userChanged?.LastName.Should().Be(request.LastName);
    userChanged?.Username.Should().Be(request.UserName);
}

这是我测试的错误信息:

预期 userChanged?.FirstName 为“名称已更改”,长度为 12,但“名字”的长度为 10,与“Fir”(索引 0)不同。

用户更新服务还可以,因为当我使用

_context.Entry(userChanged).Reload();
时,测试用例是绿色的。

非常感谢您的想法或建议...

c# asp.net entity-framework testing testcontainers
1个回答
0
投票

这是因为您在用于创建用户的同一个

FindAsync
实例上使用
DbContext
。创建用户后,将其存储在
DbContext
缓存中。
FindAsync
首先检查此缓存并返回过时的用户对象。

© www.soinside.com 2019 - 2024. All rights reserved.