在集成测试之间重置内存数据库 [英] Resetting In-Memory database between integration tests

查看:22
本文介绍了在集成测试之间重置内存数据库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经建立了一个基于 https://github.com/jasontaylordev/CleanArchitecture.但是我在为控制器编写集成测试时遇到了一些麻烦,因为内存数据库不会在每次测试之间重置.每个测试都使用 WebApplicationFactory 来设置测试 Web 服务器,

I've set up a project based on https://github.com/jasontaylordev/CleanArchitecture. But I'm having some troubles with writing my integration tests for the controllers, since the in-memory database does not reset between each test.Each test use a WebApplicationFactory in order to set up a test web server,

public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
    {
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            builder.ConfigureServices(services =>
                {
                    // Remove the app's ApplicationDbContext registration.
                    var descriptor = services.SingleOrDefault(
                        d => d.ServiceType ==
                            typeof(DbContextOptions<ApplicationDbContext>));

                    if (descriptor != null)
                    {
                        services.Remove(descriptor);
                    }

                    // Add a database context using an in-memory 
                    // database for testing.
                    services.AddDbContext<ApplicationDbContext>(options =>
                    {
                        options.UseInMemoryDatabase("InMemoryDbForTesting");
                    });

                    // Register test services
                    services.AddScoped<ICurrentUserService, TestCurrentUserService>();
                    services.AddScoped<IDateTime, TestDateTimeService>();
                    services.AddScoped<IIdentityService, TestIdentityService>();

                    // Build the service provider
                    var sp = services.BuildServiceProvider();

                    // Create a scope to obtain a reference to the database
                    // context (ApplicationDbContext).
                    using (var scope = sp.CreateScope())
                    {
                        var scopedServices = scope.ServiceProvider;
                        var context = scopedServices.GetRequiredService<ApplicationDbContext>();
                        var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();

                        // Ensure the database is created.
                        context.Database.EnsureCreated();

                        try
                        {
                            // Seed the database with test data.
                            SeedSampleData(context);
                        }
                        catch (Exception ex)
                        {
                            logger.LogError(ex, "An error occurred seeding the database with test messages. Error: {Message}", ex.Message);
                        }
                    }
                })
                .UseEnvironment("Test");
        }
    ...

以下创建测试的地方:

namespace CleanArchitecture.WebUI.IntegrationTests.Controllers.TodoItems
{
    public class Create : IClassFixture<CustomWebApplicationFactory<Startup>>
    {
        private readonly CustomWebApplicationFactory<Startup> _factory;

        public Create(CustomWebApplicationFactory<Startup> factory)
        {
            _factory = factory;
        }

        [Fact]
        public async Task GivenValidCreateTodoItemCommand_ReturnsSuccessCode()
        {
            var client = await _factory.GetAuthenticatedClientAsync();

            var command = new CreateTodoItemCommand
            {
                Title = "Do yet another thing."
            };

            var content = IntegrationTestHelper.GetRequestContent(command);

            var response = await client.PostAsync($"/api/todoitems", content);

            response.EnsureSuccessStatusCode();
        }
    ...

以及以下读取测试:

namespace CleanArchitecture.WebUI.IntegrationTests.Controllers.TodoItems
{
    public class Read: IClassFixture<CustomWebApplicationFactory<Startup>>
    {
        private readonly CustomWebApplicationFactory<Startup> _factory;

        public Read(CustomWebApplicationFactory<Startup> factory)
        {
            _factory = factory;
        }

        [Fact]
        public async Task ShouldRetriveAllTodos()
        {
            var client = await _factory.GetAuthenticatedClientAsync();

            var response = await client.GetAsync($"/api/todoitems");

            var todos = Deserialize(response);
            todos.Count().Should().Be(1); //but is 2 because database is shared between read and create test class.
        }

问题是内存数据库在每次测试之间没有重置.我尝试使用 Guid.New.ToString 为内存数据库生成不同的名称,但是测试没有找到种子数据库数据,并将测试放在同一个 XUnit收藏,没用.

The problem is that the in-memory database is not reset between each test. I've tried generating a different name for the in-memory database using Guid.New.ToString, but then the tests don't find the seeded database data, and by putting the tests in the same XUnit collection, to no avail.

如何使测试不共享数据库的任何好主意?

Any good ideas how to make the tests not share database?

推荐答案

对我有用的是为每个 WebApplicationFactory 实例生成一个 DBName,并且我为每个测试实例化其中一个.所以测试看起来像这样:

What worked for me was to generate a DBName for each WebApplicationFactory instance, and I instantiate one of them for each test. So the test looks like this:

[Fact]
public void Test()
{
  // Arrange
  var appFactory = new WebApplicationFactory();
  // ...

  // Act
  // ...

  // Assert
  // ...
}

还有WebApplicationFactory:

    public class TestWebApplicationFactory : WebApplicationFactory<Startup>
    {
        private readonly string _dbName = Guid.NewGuid().ToString();

        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            base.ConfigureWebHost(builder);
            builder.ConfigureServices(services =>
            {
                services.AddDbContext<DbContext>(options =>
                {
                    // This is what makes a unique in-memory database per instance of TestWebApplicationFactory
                    options.UseInMemoryDatabase(_dbName);
                });
            });
        }
    }

这篇关于在集成测试之间重置内存数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆