使用最小起订量模拟 Linq `Any` 谓词
Mock Linq `Any` predicate with Moq
我正在尝试使用以下代码在我的存储库中模拟 AnyAsync
方法,但存储库始终 returns false
.
AnyAsync
的签名是:
Task<bool> AnyAsync<TEntity>(Expression<Func<TEntiry, bool>> predicate)
我尝试了以下设置:
1:
mockCustomerRepository.Setup(r => r.AnyAsync(c => c.Email == "some@one.com"))
.ReturnsAsync(true);
2:
Expression<Func<CustomerEntity, bool>> predicate = expr =>
expr.CustomerPerson.Email == "some@one.com";
mockCustomerRepository.Setup(r => r.AnyAsync(It.Is<Expression<Func<CustomerEntity, bool>>>
(criteria => criteria == predicate))).ReturnsAsync(true);
3:
mockCustomerRepository.Setup(r => r.AnyAsync(It.IsAny<Expression<Func<CustomerEntity, bool>>>()))
.ReturnsAsync(true);
我的测试:
public class Test
{
Mock<ICustomerRepository> mockCustomerRepository;
public Test()
{
mockCustomerRepository = new Mock<ICustomerRepository>();
}
[Fact]
public async Task CustomerTest()
{
var customer = ObjectFactory.CreateCustomer(email: "some@one.com");
var sut = new CustomerService(mockCustomerRepository.Object);
var result = await sut.ValidateCustomerAsync(customer);
.
.
.
}
}
我的CustomerService.ValidateCustomerAsync
方法:
public async Task<OperationResult> ValidateCustomerAsync(CustomerEntity customer)
{
var errors = new List<ValidationResult>();
if (await _repository.AnyAsync(c => c.Email == customer.Email))
errors.Add(new ValidationResult("blah blah")));
我也读过 this 但它也不起作用。
我认为您 运行 遇到了匹配谓词的困难。 Funcs 或 Funcs 的表达式使用引用相等性,因此仅使用 ==
来比较两个实例是行不通的。 (作为一般规则,如果你不能让 predicate1.Equals(predicate2)
变为 return true,Moq 的参数匹配器将不会匹配。)
这有点不正统,但我建议您参考 my answer to a similar question for FakeItEasy matchers,这反过来又为您指出了一些验证谓词的技术。
我所看到的应该导致这个问题的是两个选项:
1. 存储库方法不是来自您应该模拟到 return 所需值的接口,因为它没有标记 virtual
.
2.您在方法中使用的类型(TEntity
)在您使用最小起订量时不匹配。
AnyAsync<TEntity>(Expression<Func<TEntity, bool>>
你可以设置 MemberEntity
并用 CustomerEntity
调用 ValidateCustomerAsync
。
也许我错了,但据我所读的方法,return 只有一个任务,.Returns(Task.FromResult(default(object)))
可以而且应该被使用。
所以在你的情况下会是 mocksCustomerRepository.Setup(r => r.AnyAsync(c => c.Email == "some@one.com")).Returns(Task.FromResult(true));
以下代码段显示了模拟 AnyAsync
方法的正确方法:
[TestMethod]
public async Task TestMethod1()
{
var fakeCustomerRepo = new Mock<ICustomerRepository>();
var foo = false;
fakeCustomerRepo.Setup(repository => repository.AnyAsync(It.IsAny<Expression<Func<CustomerEntity, bool>>>()))
.Callback<Expression<Func<CustomerEntity, bool>>>(
expression =>
{
var func = expression.Compile();
foo = func(new CustomerEntity() {Email = "foo@gmail.com"});
})
.Returns(() => Task.FromResult(foo));
var customer = new CustomerEntity() {Email = "foo@gmail.com"};
var result = await fakeCustomerRepo.Object.AnyAsync<CustomerEntity>(c => c.Email == customer.Email);
Assert.IsTrue(result);
customer = new CustomerEntity() { Email = "boo@gmail.com" };
result = await fakeCustomerRepo.Object.AnyAsync<CustomerEntity>(c => c.Email == customer.Email);
Assert.IsFalse(result);
}
使用上述设置,您可以验证作为单元行为一部分的谓词。
我正在尝试使用以下代码在我的存储库中模拟 AnyAsync
方法,但存储库始终 returns false
.
AnyAsync
的签名是:
Task<bool> AnyAsync<TEntity>(Expression<Func<TEntiry, bool>> predicate)
我尝试了以下设置:
1:
mockCustomerRepository.Setup(r => r.AnyAsync(c => c.Email == "some@one.com"))
.ReturnsAsync(true);
2:
Expression<Func<CustomerEntity, bool>> predicate = expr =>
expr.CustomerPerson.Email == "some@one.com";
mockCustomerRepository.Setup(r => r.AnyAsync(It.Is<Expression<Func<CustomerEntity, bool>>>
(criteria => criteria == predicate))).ReturnsAsync(true);
3:
mockCustomerRepository.Setup(r => r.AnyAsync(It.IsAny<Expression<Func<CustomerEntity, bool>>>()))
.ReturnsAsync(true);
我的测试:
public class Test
{
Mock<ICustomerRepository> mockCustomerRepository;
public Test()
{
mockCustomerRepository = new Mock<ICustomerRepository>();
}
[Fact]
public async Task CustomerTest()
{
var customer = ObjectFactory.CreateCustomer(email: "some@one.com");
var sut = new CustomerService(mockCustomerRepository.Object);
var result = await sut.ValidateCustomerAsync(customer);
.
.
.
}
}
我的CustomerService.ValidateCustomerAsync
方法:
public async Task<OperationResult> ValidateCustomerAsync(CustomerEntity customer)
{
var errors = new List<ValidationResult>();
if (await _repository.AnyAsync(c => c.Email == customer.Email))
errors.Add(new ValidationResult("blah blah")));
我也读过 this 但它也不起作用。
我认为您 运行 遇到了匹配谓词的困难。 Funcs 或 Funcs 的表达式使用引用相等性,因此仅使用 ==
来比较两个实例是行不通的。 (作为一般规则,如果你不能让 predicate1.Equals(predicate2)
变为 return true,Moq 的参数匹配器将不会匹配。)
这有点不正统,但我建议您参考 my answer to a similar question for FakeItEasy matchers,这反过来又为您指出了一些验证谓词的技术。
我所看到的应该导致这个问题的是两个选项:
1. 存储库方法不是来自您应该模拟到 return 所需值的接口,因为它没有标记 virtual
.
2.您在方法中使用的类型(TEntity
)在您使用最小起订量时不匹配。
AnyAsync<TEntity>(Expression<Func<TEntity, bool>>
你可以设置 MemberEntity
并用 CustomerEntity
调用 ValidateCustomerAsync
。
也许我错了,但据我所读的方法,return 只有一个任务,.Returns(Task.FromResult(default(object)))
可以而且应该被使用。
所以在你的情况下会是 mocksCustomerRepository.Setup(r => r.AnyAsync(c => c.Email == "some@one.com")).Returns(Task.FromResult(true));
以下代码段显示了模拟 AnyAsync
方法的正确方法:
[TestMethod]
public async Task TestMethod1()
{
var fakeCustomerRepo = new Mock<ICustomerRepository>();
var foo = false;
fakeCustomerRepo.Setup(repository => repository.AnyAsync(It.IsAny<Expression<Func<CustomerEntity, bool>>>()))
.Callback<Expression<Func<CustomerEntity, bool>>>(
expression =>
{
var func = expression.Compile();
foo = func(new CustomerEntity() {Email = "foo@gmail.com"});
})
.Returns(() => Task.FromResult(foo));
var customer = new CustomerEntity() {Email = "foo@gmail.com"};
var result = await fakeCustomerRepo.Object.AnyAsync<CustomerEntity>(c => c.Email == customer.Email);
Assert.IsTrue(result);
customer = new CustomerEntity() { Email = "boo@gmail.com" };
result = await fakeCustomerRepo.Object.AnyAsync<CustomerEntity>(c => c.Email == customer.Email);
Assert.IsFalse(result);
}
使用上述设置,您可以验证作为单元行为一部分的谓词。