Codeacula Codeacula - 3 months ago 17
C# Question

Is this a bad Moq setup or a deficiency in Moq?

I am attempting to test the following code:

public async Task<Activity> Get(long ID, Recruiter User, bool IsArchived = false)
{
Activity result = await collection.FirstOrDefault(x => x.ID == ID && x.Recruiter.CompanyID == User.CompanyID && (!x.Archived || IsArchived));
return result;
}


With the following test:

[TestMethod]
public async Task GetDoesThings()
{
long ID = 1;
bool IsArchived = false;
Recruiter User = new Recruiter()
{
CompanyID = 1
};

ActivitiesMock.Setup(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived))).ReturnsAsync(new Activity());

Activity result = await repo.Get(ID, User);

ActivitiesMock.Verify(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)));
}


(I know there are different ways of writing it, this is the most recent iteration we've tried.)

The
ActivitiesMock
relates to the
collection
found in
Get(long ID, Recruiter User, bool IsArchived = false)
. We recently wrote wrappers in order to try and test our Entity calls more efficiently, but we're running into this error when trying to verify the calls are made correctly:


Test method ExampleProject.Tests.Backend.Repositories.ActivityRepositoryTests.GetDoesThings threw exception:
Moq.MockException:
Expected invocation on the mock at least once, but was never performed: x => x.FirstOrDefault(y => (y.ID == .ID && y.Recruiter.CompanyID == .User.CompanyID) && (!(y.Archived) || .IsArchived))

Configured setups:
x => x.FirstOrDefault(y => (y.ID == .ID && y.Recruiter.CompanyID == .User.CompanyID) && (!(y.Archived) || .IsArchived)), Times.Never

Performed invocations:
IAppCollection`2.FirstOrDefault(x => (((x.ID == value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).ID) AndAlso (x.Recruiter.CompanyID == value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).User.CompanyID)) AndAlso (Not(x.Archived) OrElse value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).IsArchived)))


In this instance the wrapper (
collection
) is a mock of the interface. The goal is to ensure that the repository is calling the correct expression on the wrapper, so that we know the predicate that's being passed to the Entity DbSet is correct without having to worry about all the messy async abstractions.

The Mock
Setup()
with the full predicate doesn't appear to be found when the test is ran, and when I change the
Setup()
to
It.IsAny<Expression<Func<Activity, bool>>>()
it runs the mock and provides the return, but the
Verify
call doesn't work. So, running:

ActivitiesMock.Setup(x => x.FirstOrDefault(It.IsAny<Expression<Func<Activity, bool>>>())).ReturnsAsync(new Activity());

Activity result = await repo.Get(ID, User);

Assert.IsNotNull(result);
ActivitiesMock.Verify(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)));


Passes the assert but fails the Verify, whereas running:

ActivitiesMock
.Setup(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)))
.ReturnsAsync(new Activity())
.Verifiable();

Activity result = await repo.Get(ID, User);

Assert.IsNotNull(result);
ActivitiesMock.Verify();


Fails on the assert.

It looks like it's failing because it's expecting the same object types. Am I trying to do something that Moq can't handle, or am I missing something that I need to do in order to get the verification to be correct?

By request, the concrete implementation of the LINQ-to-Entity wrapper (
collection
) is:

public Task<T> FirstOrDefault(Expression<Func<T, bool>> Predicate)
{
return DbSet.FirstOrDefaultAsync(Predicate);
}


Though the wrapper itself isn't being used, but an interface for it is being mocked, and it's that mock that we're testing.

Answer

The answer is neither. Since the anonymous functions have to create class instances to store the data being provided, they create DisplayClass instances to hold the data. Since those instances are being created in different namespaces (among other things) they don't pass when Moq calls .Equals against them.

We solved this problem by writing our tests as such:

ActivitiesMock
    .Setup(x => x.Where(It.IsAny<Expression<Func<Activity, bool>>>()))
    .Returns((Expression<Func<Activity, bool>> x) =>
    {
        actualPredicate = x;
        return queryMock.Object;
    });

Then creating valid and invalid activities to provide to the predicate to ensure it returns true or false correctly:

Assert.IsTrue(actualPredicate.Compile().Invoke(validActivity));

Granted for now it's a bit hacky, but at first glance it doesn't seem too much like a dumpster fire solution, and it's a way for us to ensure the calls being provided do what we expect them to, which is what we want.

Update (Sep 7th, 2016): So far this has been working well for us. We've ran into an issue where LINQ-to-Entity statements don't run as expected because the LINQ is case-sensitive and the SQL generated isn't, but since that isn't a deal breaker for us we're just fine.