I'm trying to mock AnyAsync
method in my repository with below codes but repository always returns false
.
The signature of AnyAsync
is:
Task<bool> AnyAsync<TEntity>(Expression<Func<TEntiry, bool>> predicate)
I tried the following setups:
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);
My test:
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);
.
.
.
}
}
My CustomerService.ValidateCustomerAsync
method:
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")));
I've also read this but it doesn't work too.
The following snippet shows the correct way to mock your AnyAsync
method:
[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);
}
using the above setup you can verify your predicate which is part of your unit behavior.
I think you're running into the difficulties of matching predicates. Funcs or expressions of Funcs use reference-equality, so just using ==
to compare the two instances isn't going to work. (As a general rule, if you can't get predicate1.Equals(predicate2)
to return true, Moq's argument matchers aren't going to match.)
This is a little unorthodox, but I refer you to my answer to a similar question for FakeItEasy matchers , which in turn points you at a number of techniques for validating predicates.
All I can see that should cause this problem are two options:
1. The repository method does not come from an interface that you should mock to return the desired value, as it is not marked with virtual
.
2. The types ( TEntity
) you use in method do not match when you are using the moq.
AnyAsync<TEntity>(Expression<Func<TEntity, bool>>
as you can setup for let's say MemberEntity
and call the ValidateCustomerAsync
with a CustomerEntity
.
Maybe I am wrong but, but as far as I have read for methods that return only a Task, .Returns(Task.FromResult(default(object)))
can and should be used.
So in your case it would be mocksCustomerRepository.Setup(r => r.AnyAsync(c => c.Email == "some@one.com")).Returns(Task.FromResult(true));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.