仅将记录添加到内存数据库一次

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

我正在尝试使用数据库编写我的第一个 xunit 测试,而不是嘲笑 DbContext,我在文章中读到时使用了 inMemoryDatabase,所以我喜欢以下

公共类 GetCustomersTest { DbContextOptions _context;

    public GetCustomersTest()
    {
        if (_context==null)
            _context = CreateContextForCustomer();
    }        
    
    [Theory]
    [InlineData(1)]
    [InlineData(2)]
    public void GetCustomerById_ShouldReturnCorrectObject(int id)
    {
        using (var context = new DataBaseContext(_context))
        {
            var customerByIdService = new GetCustomerByIdService(context);
            
            var customer = customerByIdService.Execute(id);
            var customerActual = context.Customers.Where(x => x.Id == id).SingleOrDefault();
            var customerTmp = new Customer()
            {
                Id = id,
                FirstName = customer.Data.FirstName,
                LastName = customer.Data.LastName,
                Phone = customer.Data.Phone,
                ClientNote = customer.Data.ClientNote
            };
            Assert.Equal(customerTmp.FirstName, customerActual.FirstName);
            Assert.Equal(customerTmp.LastName, customerActual.LastName);
            Assert.Equal(customerTmp.Phone, customerActual.Phone);
            Assert.Equal(customerTmp.ClientNote, customerActual.ClientNote);

        }
    }

    private DbContextOptions<DataBaseContext> CreateContextForCustomer() {

        var options = new DbContextOptionsBuilder<DataBaseContext>()
            .UseInMemoryDatabase(databaseName: "SalonDatabase")
            .Options;

        using (var context = new DataBaseContext(options))
        {
            context.Customers.Add(new Customer
            {
                Id = 1,
                FirstName = "User1",
                LastName = "Surname1",
                Phone = "123",
                ClientNote = ""
            });
            context.Customers.Add(new Customer
            {
                Id = 2,
                FirstName = "User2",
                LastName = "Surname2",
                Phone = "4567",
                ClientNote = "The best"
            });
            
            context.SaveChanges();
        }
        return options;
    }
}

它可以在 [InlineData(1)] 上找到,但是当谈到 [InlineData(2)] 时,它似乎再次开始运行构造函数,因此当它想要将 customerdata 添加到表中时,它说记录该 Id 密钥已存在。最好的方法是什么?

c# xunit in-memory-database
2个回答
0
投票

构建数据库上下文选项时,将 GUID 添加到数据库名称以使其唯一:

var options = new DbContextOptionsBuilder<DataBaseContext>()
    .UseInMemoryDatabase(databaseName: "SalonDatabase" + Guid.NewGuid().ToString())
    .Options;

或者,如果您使用的是足够新的语言版本,您可以使用字符串插值而不是连接:

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

如果您这样做,那么每个测试都会使用全新的数据库,不受之前任何测试的影响。

正如 @MicheleMassari 所说,遵循 Arrange Act Assert 模式是一个很好的做法,这样就可以清楚哪些行正在为测试做好准备,哪些行正在执行您想要测试其结果的操作。

  1. 安排投入和目标。安排步骤应该设置测试用例。测试是否需要任何对象或特殊设置?需要准备数据库吗?是否需要登录网络应用程序?在测试开始时处理所有这些操作。
  2. 按照目标行为采取行动。行动步骤应该涵盖要测试的主要内容。这可能是调用函数或方法、调用 REST API 或与网页交互。让行动集中在目标行为上。
  3. 断言预期结果。行动步骤应该引起某种反应。断言步骤验证该响应的好坏。有时,断言就像检查数字或字符串值一样简单。其他时候,他们可能需要检查系统的多个方面。断言将最终决定测试是否通过。

该页面中的代码示例是用 Python 而不是 C# 编写的,但该模式对于任何语言的单元测试都有效。就您的测试而言,以这种方式构建测试可以清楚地表明您正在测试

GetCustomerByIdService.Execute
的行为还是实体框架的
Where
方法的行为。


0
投票

我认为为每个测试创建一个新数据库(以及内存中......)不是一个好的做法。

问题是您正在测试类的构造函数中填充数据库。

xUnit 文档 说:

xUnit.net 为每个运行的测试创建一个新的测试类实例,因此放置到测试类构造函数中的任何代码都将为每个测试运行。

相反,你应该使用固定装置:

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