我正在尝试使用数据库编写我的第一个 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 密钥已存在。最好的方法是什么?
构建数据库上下文选项时,将 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 模式是一个很好的做法,这样就可以清楚哪些行正在为测试做好准备,哪些行正在执行您想要测试其结果的操作。
- 安排投入和目标。安排步骤应该设置测试用例。测试是否需要任何对象或特殊设置?需要准备数据库吗?是否需要登录网络应用程序?在测试开始时处理所有这些操作。
- 按照目标行为采取行动。行动步骤应该涵盖要测试的主要内容。这可能是调用函数或方法、调用 REST API 或与网页交互。让行动集中在目标行为上。
- 断言预期结果。行动步骤应该引起某种反应。断言步骤验证该响应的好坏。有时,断言就像检查数字或字符串值一样简单。其他时候,他们可能需要检查系统的多个方面。断言将最终决定测试是否通过。
该页面中的代码示例是用 Python 而不是 C# 编写的,但该模式对于任何语言的单元测试都有效。就您的测试而言,以这种方式构建测试可以清楚地表明您正在测试
GetCustomerByIdService.Execute
的行为还是实体框架的 Where
方法的行为。