我已经使用 XUnit 和 Moq 编写了一些测试。模拟接口(interface)实现的一种方法是接受 Expression<Func<T, bool>>
类型的参数。一切似乎都运行良好,但我无法理解验证该方法是否使用正确的表达式调用的工作。
给定以下测试,即使调用看起来正确,该方法也不会返回设置中指定的值:
/// <summary>
/// Verify that a create fails appropriately when another entity was found given the same name,
/// Verify that the message of the exception contains the duplicate name
/// Verify that update fails before other calls are made
/// </summary>
[Theory(DisplayName = "Definition Types service - Create")]
[MemberData(nameof(DefinitionTypesTestData.SingleDefinitionType), MemberType = typeof(DefinitionTypesTestData))]
public async Task CreateDefinitionTypeShouldThrowDuplicateTest(DefinitionType obj)
{
if (obj == null) throw new NullReferenceException($"Test data was null in theory 'Definition Types service - Create'");
var crudService = new Mock<IEntityCrudService<DefinitionType>>();
crudService.Setup(crud => crud.GetEntitiesAsync(x => x.Name == obj.Name))
.Returns(Task.FromResult<IEnumerable<DefinitionType>>(new List<DefinitionType> {
new DefinitionType {
Name = "Test",
Description = "Test",
DisplayName = "Test",
ID = Guid.NewGuid()
} }));
IDefinitionTypesService serviceUnderTest = new DefinitionTypesService(crudService.Object);
var exception = await Assert.ThrowsAsync<EntityDuplicationException>(() => serviceUnderTest.InsertDefinitionTypeAsync(obj));
Assert.Contains("Definition type", exception.DisplayMessage);
Assert.Contains(obj.Name, exception.DisplayMessage);
crudService.Verify(crud => crud.GetEntitiesAsync(x => x.Name == obj.Name), Times.Once);
crudService.VerifyNoOtherCalls();
}
我对 InsertDefinitionType(DefinitionType obj) 有以下实现:
async Task IDefinitionTypesService.InsertDefinitionTypeAsync(DefinitionType obj)
{
var definitiontypes = await _definitionTypeService.GetEntitiesAsync(x => x.Name == obj.Name);
if(definitiontypes.Any())
{
throw new EntityDuplicationException("Definition type", name: obj.Name);
}
try
{
await _definitionTypeService.CreateAsync(obj);
}
catch (EntityNotSavedException exc)
{
exc.EntityType = "Definition type";
throw exc;
}
}
当我如下更改我的设置时,我确实得到了结果,但在我的验证函数中它说该函数从未被调用(或至少使用给定的表达式)。 :
crudService.Setup(crud => crud.GetEntitiesAsync(It.IsAny<Expression<Func<DefinitionType, bool>>>()))
.Returns(Task.FromResult<IEnumerable<DefinitionType>>(new List<DefinitionType> {
new DefinitionType {
Name = "Test",
Description = "Test",
DisplayName = "Test",
ID = Guid.NewGuid()
} }));
现在,我还将验证更改为更通用:
crudService.Verify(crud => crud.GetEntitiesAsync(It.IsAny<Expression<Func<DefinitionType, bool>>>()), Times.Once);
现在我的测试通过了,但我真的想验证该方法是否被正确调用而不是被调用。我如何以最简单/最好的方式解决这个问题?
最佳答案
您需要更具体地了解设置中使用的表达式。
使用It.Is<T>()
并调用表达式进行设置和验证。
[Theory(DisplayName = "Definition Types service - Create")]
[MemberData(nameof(DefinitionTypesTestData.SingleDefinitionType), MemberType = typeof(DefinitionTypesTestData))]
public async Task CreateDefinitionTypeShouldThrowDuplicateTest(DefinitionType obj) {
if (obj == null) throw new NullReferenceException($"Test data was null in theory 'Definition Types service - Create'");
//Arrange
var crudService = new Mock<IEntityCrudService<DefinitionType>>();
var list = new List<DefinitionType>() {
new DefinitionType {
Name = "Test",
Description = "Test",
DisplayName = "Test",
ID = Guid.NewGuid()
}
};
crudService
.Setup(_ => _.GetEntitiesAsync(It.Is<Expression<Func<DefinitionType, bool>>>(exp => exp.Compile()(obj))))
.ReturnsAsync(list);
IDefinitionTypesService serviceUnderTest = new DefinitionTypesService(crudService.Object);
//Act
var exception = await Assert.ThrowsAsync<EntityDuplicationException>(() => serviceUnderTest.InsertDefinitionTypeAsync(obj));
//Assert
Assert.Contains("Definition type", exception.DisplayMessage);
Assert.Contains(obj.Name, exception.DisplayMessage);
crudService.Verify(_ => _.GetEntitiesAsync(It.Is<Expression<Func<DefinitionType, bool>>>(exp => exp.Compile()(obj))), Times.Once);
crudService.VerifyNoOtherCalls();
}
请特别注意设置和验证中使用的表达式。
_ => _.GetEntitiesAsync(It.Is<Expression<Func<DefinitionType, bool>>>(exp => exp.Compile()(obj)))
关于c# - 如何验证使用正确表达式调用的模拟异步方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54808584/