为了进行集成测试,我使用 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();
时,测试用例是绿色的。
非常感谢您的想法或建议...
这是因为您在用于创建用户的同一个
FindAsync
实例上使用 DbContext
。创建用户后,将其存储在 DbContext
缓存中。 FindAsync
首先检查此缓存并返回过时的用户对象。