Kevin
Kevin

Reputation: 16013

Moq an IQueryable that returns itself

I'm setting up a test using a mocked IQueryable (using Moq) that I want to return itself when .Where() is called on it:

[SetUp]
public void Setup() {
    mockPocos = new Mock<IQueryable<Poco>>();
    mockPocos.Setup(foo => foo.Where(It.IsAny<Expression<Func<Poco, bool>>>()))
        .Returns(mockPocos.Object);
}

(This way, I can mock methods/properties like .Count and know that regardless of how many times the method being tested runs queries over the IQueryable, it will return values I can control.)

This compiles, but when I run it, I get this exception:

Tests.PocoTest.TestPocoQueryable:
SetUp : System.NotSupportedException : Expression references a method that does not belong to the mocked object: foo => foo.Where<Poco>(It.IsAny<Expression`1>())

How can I get this to work?


EDIT: In response to the comments, this is why I want to use Moq like this.

In the method I'm testing, I have code like this:

public int[] MethodToTest(IQueryable<Poco> pocos, MockableDependency dependency)
{
    var mostRecentUpdate = (from poco in pocos
                                select poco.Date_Last_Updated).Max();
    var recentPocos = pocos.Where(x => x.Date_Last_Updated.CompareTo(mostRecentUpdate) >= 0);

    ///...snip...

    result[0] = SomePrivateCalculation(recentPocos.Count);
    result[1] = dependency.DoADifferentCalculation(recentPocos);
}

I'm already mocking the MockableDependency, so I don't actually need to worry about what Pocos are in pocos. However, I would like to be able to control what the value of recentPocos.Count is, and I would like to be able to know that it will return the same value no matter how many queries are run over pocos before .Count is accessed.

Upvotes: 0

Views: 1374

Answers (1)

MattiasG is hinting at the solution. You should be providing an IQuerable pocos that will always generate a query with a known result giving you the .Count you'd expect.

So what is not shown in code here, is that correctly done; the method that is passing pocos should be mocked as well to provide for the data that you can make proper assertions on.

It is hard to find a good balance of testing. It's an art form really. But if you are using moq you should focus on high order 'Unit-Of-Work' and not what is going on inside individual methods.

To put this in other words. Let's say you manage to get Count to always return 5. And then you have a test checking if Count is 5 in your dependency method. It is. What have you accomplished? Well, you can assert that Count will return an int (we kinda know this is working already), but you haven't really tested your application code at all.

But to answer your actual question: - You would have to make a new interface IMyOwnCustomMockableQuery<>, with some converter or wrapper class to IQuearble<> and then a new linq implementation for your IMyOwnCustomMockableQuery<> that forwards all calls you don't want to mock to the exensions on IQuearble<>.

Sure this would be quite complicated and demand its own tests. =) Seems like a lot of work for testing your mockup for tests that don't test your application. I would not recommend this approach.

Upvotes: 1

Related Questions