EF核心:使用InMemory数据库进行测试具有不一致的行为

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

我正在使用InMemory数据库来测试我的ASP .NET Core Web API应用程序中的存储库层。因此,在几个测试中,我会设置数据。但是,使用相同的代码,当我运行测试时,有时会存在数据,有时却没有。我不明白为什么。

我正在使用XUnit测试框架。

这是我的测试:

public class UserRepositoryTest
    {
        private ApplicationDbContext context;

        void setup()
        {
            var options = new DbContextOptionsBuilder<ApplicationDbContext>()
                .UseInMemoryDatabase(databaseName: "ApplicationDatabase")
                .Options;

            this.context = new ApplicationDbContext(options);
            this.context.Database.EnsureDeleted();
        }

        [Fact]
        void GetUserByUsernameTest()
        {
            this.setup();
            // Given
            var manager = new User {Username = "Ombrelin", Email = "[email protected]"};
            context.Users.Add(manager);
            context.SaveChanges();

            // When 
            var repo = new UserRepository(context);
            var user = repo.GetUserByUsername("Ombrelin");

            // Then
            Assert.Equal("Ombrelin", user.Username);
        }

        [Fact]
        void FindUsersByUsernameContainsTest()
        {
            this.setup();
            // Given
            var manager1 = new User {Username = "Arsène", Email = "[email protected]"};
            var manager2 = new User {Username = "Jean Michel", Email = "[email protected]"};
            context.Users.Add(manager1);
            context.Users.Add(manager2);
            context.SaveChanges();

            // When 
            var repo = new UserRepository(context);
            var users = repo.findUsersByUsernameContains("Ars");

            // Then
            Assert.Single(users);
        }

有人对此有任何线索吗?

谢谢,

c# unit-testing asp.net-core .net-core in-memory-database
1个回答
0
投票

您正在多个测试中重用同一数据库上下文。测试可以并行运行。因此,当使用相同的数据库时,上下文测试可能会影响彼此的结果。为了避免这种情况,您需要通过允许测试使用干净的数据库上下文来隔离测试:

public class UserRepositoryTest
{
    [Fact]
    public void GetUserByUsernameTest()
    {

        var options = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName: $"ApplicationDatabase{Guid.NewGuid()}")
            .Options;

        using(var context = new ApplicationDbContext(options))
        {
            // Given
            var manager = new User { Username = "Ombrelin", Email = "[email protected]" };
            context.Users.Add(manager);
            context.SaveChanges();

            // When 
            var repo = new UserRepository(context);
            var user = repo.GetUserByUsername("Ombrelin");

            // Then
            Assert.Equal("Ombrelin", user.Username);
        }

    }
}

通过向数据库名称添加唯一的ID,您可以确保测试使用的是唯一的内存数据库。显然,这会使测试执行速度变慢。许多测试人员还使用不同的上下文来播种数据并执行测试:

public class UserRepositoryTest
{
    [Fact]
    public void GetUserByUsernameTestSeparateContexts()
    {

        var options = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName: $"ApplicationDatabase{Guid.NewGuid()}")
            .Options;

        using (var context = new ApplicationDbContext(options))
        {
            // Given
            var manager = new User { Username = "Ombrelin", Email = "[email protected]" };
            context.Users.Add(manager);
            context.SaveChanges();

        }

        using (var context = new ApplicationDbContext(options))
        {
            // When 
            var repo = new UserRepository(context);
            var user = repo.GetUserByUsername("Ombrelin");

            // Then
            Assert.Equal("Ombrelin", user.Username);
        }

    }
}

这使测试更加切合实际,因为作为数据种子的函数和使用数据的函数通常使用不同的上下文。还请记住,InMemoryProvider不是关系数据库。因此,它不支持实际数据库服务器的某些功能,例如参照完整性检查,TimeStamp,IsRowVersion等。有关详细信息,请参阅MS文档:here

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