Reputation: 11564
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 == "[email protected]"))
.ReturnsAsync(true);
2:
Expression<Func<CustomerEntity, bool>> predicate = expr =>
expr.CustomerPerson.Email == "[email protected]";
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: "[email protected]");
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.
Upvotes: 3
Views: 3696
Reputation: 8725
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 = "[email protected]"});
})
.Returns(() => Task.FromResult(foo));
var customer = new CustomerEntity() {Email = "[email protected]"};
var result = await fakeCustomerRepo.Object.AnyAsync<CustomerEntity>(c => c.Email == customer.Email);
Assert.IsTrue(result);
customer = new CustomerEntity() { Email = "[email protected]" };
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.
Upvotes: 5
Reputation: 156
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 == "[email protected]")).Returns(Task.FromResult(true));
Upvotes: 0
Reputation: 6623
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
.
Upvotes: 0
Reputation: 242100
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.
Upvotes: 2