如何使用WebApplicationFactory生成测试数据的种子数据?

3

我正在为 .NET Core 3.1 Web API 进行集成测试。我按照这篇文章《ASP.NET Core Web API的无痛集成测试》进行操作。这是我的CustomWebApplicationFactory

public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<TestDbContext>));
            if (descriptor != null)
            {
                services.Remove(descriptor);
            }

            services.AddDbContext<TestDbContext>(options =>
            {
                options.UseInMemoryDatabase("InMemoryTestDb");
            });

            var sp = services.BuildServiceProvider();

            using (var scope = sp.CreateScope())
            {
                var scopedServices = scope.ServiceProvider;
                var db = scopedServices.GetRequiredService<TestDbContext>();
                var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();

                db.Database.EnsureCreated();

                try
                {
                    Console.WriteLine("Seeding...");

                    var players = Utilities.GetTestPlayers(); // Returns 3 test players
                    db.Players.RemoveRange(db.Players); // Clear the table
                    db.Players.AddRange(players); // Add 3 test players
                    db.SaveChanges();

                    Console.WriteLine($"Players seeded: { db.Players.Count() }");
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, "An error occurred seeding the " + "database with test messages. Error: {Message}", ex.Message);
                }
            }
        });
    }
}

这是我的测试: 对于每个控制器(Controller),我都会创建一个单独的测试类。在测试类的构造函数中,我会创建一个客户端(Client)。就像对于TestController(API中共有4个控制器):

public class BaseControllerTest : IClassFixture<CustomWebApplicationFactory<Startup>>
{
    protected HttpClient Client { get; }

    public BaseControllerTest(CustomWebApplicationFactory<Startup> factory)
    {
        Client = factory.CreateClient();
    }
}

public class TestControllerShould : BaseControllerTest
{
    public TestControllerShould(CustomWebApplicationFactory<Startup> factory)
        : base(factory)
    {
        Console.WriteLine("TestControllerShould");
    }

    [Fact]
    public async Task GetHelloWorld()
    {
        var request = new HttpRequestMessage(new HttpMethod("GET"), "/test/");
        var response = await Client.SendAsync(request);

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        var content = await response.Content.ReadAsStringAsync();
        Assert.Equal("Hello World!", content);
        Assert.False(response.Headers.Contains("Server"), "Should not contain server header");
    }
} 

我的问题是:

正如您在CustomWebApplicationFactory中看到的,我正在进行日志记录,同时正在进行种子处理,这是我看到的日志:

Seeding...
Seeding...
Seeding...
Seeding...
Players seeded: 12
Players seeded: 12
Players seeded: 12
Players seeded: 12

我总共有4个控制器,但只播种了3个玩家。为什么我看到的是12个?我不明白。看起来在任何db.SaveChanges();之前,每个控制器测试类都会调用db.Players.AddRange(players); 4次。然后连续4次调用了db.SaveChanges();。为什么?
我的问题是:为什么会这样?如何正确地在集成测试中种植测试数据?
(如果不是通过答案,请引用一篇好的文章将非常感谢)
谢谢

你可能会在决定从内存切换到实际数据库用于集成测试时,找到这个链接(https://github.com/v-zubritsky/Reseed)很有帮助。我正在根据自己的需求进行开发,但也乐意帮助他人。 - Uladzislaŭ
1个回答

2

对于每个控制器,它都会调用ConfigureServices。因此,在调用db.Database.EnsureCreated()之前,您可以执行以下操作:db.Database.EnsureDeleted()。这将重新初始化内存数据库以供每个控制器使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接