Mock Linq `Any` predicate with Moq - c#

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));

Related

Xunit - Moq always returns a null value even after setup

Hi I am having an issue with my moq when I try to return data, I saw this questtion with a solution but it doesn't work on my side.
Can anyone please tell me what I'm doing wrong
Here is my respository
private readonly IRepository<SomeClass<MyObject>> repository;
public MyObjectRepository(IRepositoryFactory factory)
{
repository = factory.RepositoryOf<SomeClass<MyObject>>();
}
public async Task<IEnumerable<MyObject>> GetAllAsync(string SomeParameter)
{
var result = await repository.GetAsync(x => x.OtherParameter == $"{SomeParameter}.{nameof(MyObject)}s", default);
var reportDataItem = result.FirstOrDefault();
if (reportDataItem == null)
return null;
return reportDataItem.Collection;
}
Here is my test
var data = await MockDBHelper.GetAirportsAsync(someParameter, true);
mockIRepository.Setup(x => x.GetAsync(null, default)).ReturnsAsync(data);
mockFactory.Setup(x => x.RepositoryOf<SomeClass<MyObject>>()).Returns(mockIRepository.Object);
_repo = new MyObjectRepository(mockFactory.Object);
var result = await _repo.GetAllAsync(AirlineCd);
mockRepository.Verify(x => x.GetAsync(null,default), Times.Once());
This statement
mockIRepository.Setup(x => x.GetAsync(null, default)).ReturnsAsync(data);
will only return data when the values of null and the default value are passed as the two parameters. Since you are passing a function as the first parameter it is not null, therefore not matching the setup. Instead you could tell mock to "Match anything" for the function.
mockIRepository.Setup(x => x.GetAsync(It.IsAny<Func<PARAMETER_TYPE, RETURN_TYPE>>(), default)).ReturnsAsync(data);
You will need to replace PARAMETER_TYPE and RETURN_TYPE with the appropriate types used in your code.

Setup a mocked EF Service method

I have the following method in my NewsDataService class
public IEnumerable<NewsModel> GetImportantNews()
{
var result = this.newsfeedRepository.GetAll(
x => x.IsImportant == true,
x => new NewsModel()
{
Creator = x.User.UserName,
AvatarPictureUrl = x.User.AvatarPictureUrl,
Content = x.Content,
CreatedOn = x.CreatedOn
})
.OrderByDescending(x => x.CreatedOn);
return result;
}
My question is...
How do I setup the mocked service method (GetImportantNews),
so that it returns a list of NewsModel which are "Important"?
My idea is something like this, but it is not working so far, because it is always returning the full list.
var expectedResult = new List<Newsfeed>()
{
new Newsfeed()
{
IsImportant = false,
},
new Newsfeed()
{
IsImportant = true
}
};
mockedNewsfeedRepository
.Setup(x => x.GetAll(
It.IsAny<Expression<Func<Newsfeed, bool>>>(),
It.IsAny<Expression<Func<Newsfeed, NewsModel>>>()
)).Returns(expectedResult);
Basically what I want is my "expectedResult" to be filtered by the logic in the method.
You have access to the invocation arguments when returning a value. Apply the predicate and projection expression arguments to the fake data source using linq like in the example below.
mockedNewsfeedRepository
.Setup(x => x.GetAll(
It.IsAny<Expression<Func<Newsfeed, bool>>>(),
It.IsAny<Expression<Func<Newsfeed, NewsModel>>>()
))
// access invocation arguments when returning a value
.Returns((Expression<Func<Newsfeed, bool>> predicate, Expression<Func<Newsfeed, NewsModel>> projection) =>
expectedResult.Where(predicate.Compile()).Select(projection.Compile())
);
Source: Moq Quickstart

Moq cannot instantiate service that includes lambda expression

I want to mock the following method with Moq:
T GetOne(Expression<Func<T, bool>> expression);
which is called in the following method:
public GetTCNotifyFCResponse GetTCNotifyFC(string operationNumber)
{
var response = new GetTCNotifyFCResponse { IsValid = false };
try
{
var tcAbstract = _tcAbstractRepository
.GetOne(x => x.Operation.OperationNumber == operationNumber);
if (tcAbstract == null)
{
response.ErrorMessage = Localization.GetText(WORKFLOW_DONT_STARED);
return response;
}
[...]
The test code is:
var mockAbstractRep = new Mock<ITCAbstractRepository>();
mockAbstractRep
.Setup(s => s.GetOne(x => x.Operation.OperationNumber == operationNumber))
.Returns(entity);
but when running it I get a null "tcAbstract" result... "operationNumber" and "entity" variables are filled before and have not been included here for simplicity.
What am I doing wrong?
Try this and see if it helps
var mockAbstractRep = new Mock<ITCAbstractRepository>();
mockAbstractRep
.Setup(s => s.GetOne(It.IsAny<Expression<Func<EntityType, bool>>>()))
.Returns(entity);
replace EntityType with the type that your method requires

DbSet mock, no results while calling ToList secondly

I'm trying to mock DbContext and DbSet. This works for my previous unit tests, but problem occurs while my code was calling ToList method on DbSet second time.
First dbSet.ToList() returns mocked results.
Second one returns 0 elements;
var queryableData = new List<string>{ "a", "b", "c" }.AsQueryable();
var mockDbSet = new Mock<DbSet<string>>();
var q = mockDbSet.As<IQueryable<string>>();
q.Setup(m => m.Provider).Returns(queryableData.Provider);
q.Setup(m => m.Expression).Returns(queryableData.Expression);
q.Setup(m => m.ElementType).Returns(queryableData.ElementType);
q.Setup(m => m.GetEnumerator()).Returns(queryableData.GetEnumerator());
DbSet<string> dbset = mockDbSet.Object;
IQueryable<string> query = dbset;
//RESULTS: abc
var a1 = dbset.ToList();
foreach (var a in a1)
Console.Write(a);
//NO RESULTS
var a2 = dbset.ToList();
foreach (var a in a2)
Console.Write(a);
You return the very same enumerator instance upon each call to GetEnumerator. When it enumerates once, it is done, EF doesn't call its Reset method, rather it asks for a new enumerator.
But you return the one that just has yielded all elements and yields no more.
Instead, return a function that returns the enumerator, that will return a new enumerator each time you ask for it.
q.Setup(m => m.GetEnumerator()).Returns( () => queryableData.GetEnumerator() );
I just wanted to added to Wiktor Zychla's answer my little part. If someone is looking for Async version of this mock (coming from this tutorial: http://msdn.microsoft.com/en-us/data/dn314429.aspx#async) then this is my modification to TestDbAsyncEnumerator<T> class:
internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public TestDbAsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public TestDbAsyncEnumerator(Func<IEnumerator<T>> valueFunction)
{
_inner = valueFunction();
}
public void Dispose()
{
_inner.Dispose();
}
public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
{
return Task.FromResult(_inner.MoveNext());
}
public T Current
{
get { return _inner.Current; }
}
object IDbAsyncEnumerator.Current
{
get { return Current; }
}
}
Then like Wiktor suggested you have to setup it with delegate so in case of async it would be like that:
mockSet.As<IDbAsyncEnumerable<Blog>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<Blog>(() => data.GetEnumerator()));
If someone wants source for that then here you go: https://github.com/kelostrada/EntityFrameworkWithMock.Test
I can't comment on Wiktor's post as I haven't got enough reputation, but i would like to add a little extra to Wiktor's answer.
The code
mockSet.Setup((m => m.GetEnumerator()).Returns(() => data.GetEnumerator())
Will fail if you give it a zero argument lambda like in the example(At least the version I am using).
Passing an argument that is never used will allow it to meet the signature requirement however.
mockSet.Setup((m => m.GetEnumerator()).Returns(x => data.GetEnumerator())
Will compile however, and works as expected.
And this also applies to Kelu's answer as well (Although he has added the lambda in the wrong place.
mockSet.As<IDbAsyncEnumerable<Blog>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(x => new TestDbAsyncEnumerator<Blog>(data.GetEnumerator()));
Not trying to nitpick answers here, i'm just adding because i made these mistakes myself :)
If you put a "Where" clause before the .ToList() call, the data should remain present.
var a1 = dbset.Where(m => m != null).ToList();
var a2 = dbset.Where(m => m != null).ToList();

Moq Verify that Method was called with any expression

I'm new to Moq and I'm trying to Mock my repository.
The method I'm Writing a unit test for is calling the repository like this:
var paymentState = _agreementPaymentStateRepository.SingleOrDefault(
s => s.Agreement.ID == agreementID);
I'm trying to set up my moq like this:
_agreementPaymentStateRepositoryMock
.Setup(m => m.SingleOrDefault(s => s.AgreementID == 1))
.Returns(AgreementPayMentStateMocks.GetOne);
I pass my mocked repository to the class but the paymentState variable is null after the call is made. (I would gladely skip specifying the expression as well).
Any help is much appreciated.
public PaymentState GetPaymentState(int agreementID)
{
try
{
_log.AgreementPaymentStateServiceGetStateStart(agreementID);
var paymentState =
_agreementPaymentStateRepository.SingleOrDefault(s => s.Agreement.ID == agreementID);
var stateToGet = MapStateToGet(paymentState);
_log.AgreementPaymentStateServiceGetStateReturn(agreementID, paymentState.LatestStatus);
return stateToGet;
}
catch (Exception ex)
{
_log.ServiceException(ex.ToString());
throw;
}
}
and the test:
var paymentState = AgreementPayMentStateMocks.GetPayMentState();
_agreementPaymentStateRepositoryMock.Setup(m => m.SingleOrDefault(s => s.AgreementID == 1)).Returns(AgreementPayMentStateMocks.GetOne);
var service = new AgreementPaymentStateService(_agreementPaymentStateRepositoryMock.Object, _log.Object);
var result = service.GetPaymentState(1);
_agreementPaymentStateRepositoryMock.Verify(m => m.Match(aps => aps.SingleOrDefault(s => s.AgreementID == 1)), Times.Exactly(1));
Instead of having a concrete predicate in the SingleOrDefault call, use Moq's It.IsAny<T> method:
_agreementPaymentStateRepositoryMock
.Setup(m => m.SingleOrDefault(It.IsAny<Expression<Func<bool,PaymentState>>>()))
.Returns(AgreementPayMentStateMocks.GetOne);

Categories