Moq: How to get to a parameter passed to a method of a mocked service

Viewed 129682

Imagine this class

public class Foo {

    private Handler _h;

    public Foo(Handler h)
    {
        _h = h;
    }

    public void Bar(int i)
    {
        _h.AsyncHandle(CalcOn(i));
    }

    private SomeResponse CalcOn(int i)
    {
        ...;
    }
}

Mo(q)cking Handler in a test of Foo, how would I be able to check what Bar() has passed to _h.AsyncHandle?

8 Answers

An alternative is to use Capture.In, which is an out-of-the-box feature in Moq that lets you capture arguments into a collection:

//Arrange
var args = new List<SomeResponse>();
mock.Setup(h => h.AsyncHandle(Capture.In(args)));

//Act
new Foo(mock.Object).Bar(22);

//Assert
//... assert args.Single() or args.First()

This also works:

Mock<InterfaceThing> mockedObject = new Mock<InterfaceThing>();
var objectParameter = mockedObject.Invocations[1].Arguments[0] as ObjectParameter;

Lot's of good answers here! Go with the out of the box Moq feature-set until you need to make assertions about several class parameters passed to your dependencies. If you end up in that situation though, the Moq Verify feature with It.Is matchers doesn't do a good job of isolating the test failure, and the Returns/Callback way of capturing arguments adds unnecessary lines of code to your test (and long tests are a no-go for me).

Here is a gist: https://gist.github.com/Jacob-McKay/8b8d41ebb9565f5fca23654fd944ac6b with a Moq (4.12) extension I wrote that gives a more declarative way to make assertions about arguments passed to mocks, without the drawbacks aforementioned. Here is what the Verify section looks like now:

        mockDependency
            .CheckMethodWasCalledOnce(nameof(IExampleDependency.PersistThings))
            .WithArg<InThing2>(inThing2 =>
            {
                Assert.Equal("Input Data with Important additional data", inThing2.Prop1);
                Assert.Equal("I need a trim", inThing2.Prop2);
            })
            .AndArg<InThing3>(inThing3 =>
            {
                Assert.Equal("Important Default Value", inThing3.Prop1);
                Assert.Equal("I NEED TO BE UPPER CASED", inThing3.Prop2);
            });

I would be stoked if Moq provided a feature that accomplished the same thing while being as declarative and providing the failure isolation this does. Fingers crossed!

Related