简体   繁体   中英

Mock Linq `Any` predicate with Moq

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM