请告知如何在编写内存单元测试时为属性设置默认值映射。
数据库:SqlServer 存储库方法 -
public async Task<long> CreatePerson(CreatePersonRequest person)
{
try
{
Person newPerson = new Person
{
// few properties here
};
_context.Person.Add(newPerson);
await _context.SaveChangesAsync(); // Getting error on this line (Refer error below for more details)
}
}
错误:
Microsoft.EntityFrameworkCore.DbUpdateException: 'Required properties '{'IsActive'}' are missing for the instance of entity type 'Person'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the entity key value.'
注意: 这仅在单元测试中引起问题。
导致问题的属性在 dbcontext、modelBuilder 以及其他属性中定义如下
modelBuilder.Entity<Person>(entity =>
{
entity.Property(e => e.IsActive)
.IsRequired()
.HasDefaultValueSql("((1))")
.HasColumnName("Is_Active");
});
Test case
public PersonRepositoryTest()
{
DbContextOptions contextOptions = new DbContextOptionsBuilder<DBContext>()
.UseInMemoryDatabase("DBContextTest")
.ConfigureWarnings(b => b.Ignore(InMemoryEventId.TransactionIgnoredWarning))
.Options;
IConfiguration configuration = new Mock<IConfiguration>().Object;
_context = new DBContext(configuration, contextOptions);
_it = new PersonRepository(_context, _identityProvider, _lookupRepository);
}
[Fact]
public async void Should_Create_Person()
{
CreatePersonRequest request = _fixture.Create<CreatePersonRequest>();
long id = await _it.CreatePerson(request);
Assert.True(id > 0);
}
此场景更多地属于集成测试场景,或端到端测试,您最好使用新的或已知的状态数据库来端到端地运行场景。您不需要对 DbContext 创建实体或数据库实际分配新 PK 的事实进行单元测试。
存储库模式的目的是作为边界,使业务逻辑更容易测试。引入存储库为您提供了可以用模拟来替代的东西。例如,您将测试导致调用存储库的代码,而不是尝试测试存储库和扩展的 EF 是否执行其应有的操作。 (或没有)
var mockRepository = new Mock<IPersonRepository>();
mockRepository.Setup(x => x.CreatePerson(It.IsAny<CreatePersonRequest>())
.Verify(person =>
{ // Here you can add inspection logic that the CreatePersonRequest has the details you expect the code under test to pass...
});
var serviceUnderTest = new Service { PersonRepository = mockRepository.Object };
serviceUnderTest.DoWhatYouDo();
mockRepository.Verify(x => x.CreatePerson(It.IsAny<CreatePersonRequest>(), Times.Once);
作为一个非常基本的例子。目标是测试存储库除了服务低级数据操作之外不参与的业务逻辑。模拟的存储库捕获预期的调用,报告意外的调用,并模拟潜在的场景,例如如果您想在存储库抛出异常时断言行为。
当涉及到端到端测试时,您可以用内存中选项替换数据库,但我个人建议使用与生产中使用的数据库引擎相同的数据库引擎,因为许多数据库提供程序之间存在特定于提供程序的差异测试会被绊倒或错过。集成测试通常需要更长的时间来运行,并且比单元测试触发的频率要低,单元测试应该在开发期间定期运行,并在任何代码提交之前完全运行。