Can't verify method called inside Select() using Moq framework
Asked Answered
S

1

6

I have a problem with verifying that certain method was called on mock inside LINQ Select() query.

Here is the method of ContentManager I want to test:

public string ProcessElements(List<Item> items)
{
    var processed = items.Select(item => item.Process(Constants.Text));

    return Serialize(processed);
}

I want to test that Process() is called for elements of the list. My test method looks like this:

[TestMethod]
public void ProcessItems_ValidItems_ProcessCalled()
{
    var contentManager = new ContentManager();
    var itemMock = new Mock<Item>();
    itemMock.Setup(m => m.Process(It.IsAny<string>()))
        .Returns("serialized");

    contentManager.ProcessElements(new List<Item>() { itemMock.Object });

    itemMock.Verify(m => m.Process(It.IsAny<string>()), Times.Once());
}

When I run this test it fails and returns the following message:

Test method ProcessItems_ValidItems_ProcessCalled threw exception:

Moq.MockException:

Expected invocation on the mock at least once, but was never performed:

m => m.Process(It.IsAny())

No setups configured.

No invocations performed.

But if I change Select() to foreach, then test passes successfully:

public string ProcessElements(List<Item> iitem)
{
    var processed = new List<string>();
    foreach (var item in iitem)
    {
        processed.Add(item.Process(Constants.Text));
    }

    return Serialize(processed);
}

What is wrong with Moq + Select()? How can I fix this?

Sensible answered 16/5, 2018 at 11:8 Comment(0)
W
10

Not sure what .Serialize method does but .Select doesn't run the actual query it only returns an object that knows how to iterate through IEnumerable<T>.

With multiple LINQ methods like .Where, .Select you can build the query that will be lazily iterated later usually by foreach or a call to .ToList, .ToDictionary etc.

So to run the LINQ query change it from:

.Select(...)

TO:

.Select(...).ToList()

Weingarten answered 16/5, 2018 at 11:12 Comment(1)
@AlonJacobson Thank you very much! My fault that I forgot about lazy initialization.Sensible

© 2022 - 2024 — McMap. All rights reserved.