242

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?

Dariusz Woźniak
  • 9,640
  • 6
  • 60
  • 73
Jan
  • 6,532
  • 9
  • 37
  • 48
  • Did you mean "AsyncHandle" (extra "n")? And could you post the code for Handler, or specify the fully qualified type name if it's a standard type? – TrueWill Jul 17 '10 at 01:23
  • Can you show your skeleton test to show what you're thinking? While I appreciate that from your side it's obvious, from our side, it looks like someone who hasnt taken the time to make the question answerable without doing a long speculative answer. – Ruben Bartelink Jul 19 '10 at 10:12
  • 1
    There is neither a Foo nor a Bar() nor anything like this. It is just some demo code to show the situation I am in without distraction from appliction specifics. And I got just the answer, I was hoping to get. – Jan Jul 21 '10 at 21:07

8 Answers8

351

You can use the Mock.Callback-method:

var mock = new Mock<Handler>();
SomeResponse result = null;
mock.Setup(h => h.AsyncHandle(It.IsAny<SomeResponse>()))
    .Callback<SomeResponse>(r => result = r);

// do your test
new Foo(mock.Object).Bar(22);
Assert.NotNull(result);

If you only want to check something simple on the passed in argument, you also can do it directly:

mock.Setup(h => h.AsyncHandle(It.Is<SomeResponse>(response => response != null)));
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Gamlor
  • 12,978
  • 7
  • 43
  • 70
  • 67
    A side note, if you have multiple arguments to your function, you need to specify all of the types in the generic `Callback<>()` Moq method. For instance, if you method had the definition `Handler.AnsyncHandle(string, SomeResponse)`, you'd need `/* ... */.Callback(r => result = r);`. I haven't found this explicitly stated in many places, so I figured I'd add it here. – Frank Bryce Aug 31 '16 at 19:29
  • 31
    Just wanted to correct @Frank in case you haven't seen @JavaJudt answer. The properly way to get two argument is: `/* ... */.Callback((s1, s2) => { str1 = s1; result = s2});` – Renato Pereira Jun 19 '18 at 15:00
  • 9
    You can also achieve the same by just declaring the types of the arguments in the lambda expression, like so: `.Callback((string s1, SomeResponse s2) => /* stuff */ )` – jb637 May 03 '19 at 12:39
  • 2
    Could you please update your response to include a reference to the built-in `Capture.In` helper? – cao Jun 05 '19 at 07:41
  • The way `mockedObject.Invocations[0].Arguments[0]` to access arguments from @Jeff Smith is more convenient. Also a `It.Is()` matcher mentioned by @Ed Yablonsky is useful too. With these your assertions can be self-contained and do not required external variable(s). – Igor B Oct 24 '20 at 20:41
83

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()
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Johnny
  • 8,939
  • 2
  • 28
  • 33
  • 6
    Great answer! I was unaware of the Moq.Capture and Moq.CaptureMatch classes until seeing this answer. Capture is a better alternative to `Callback` IMO. Since you use Capture directly in the parameter list, it is far less prone to issues when refactoring a method's parameter list, and therefore makes tests less brittle. With Callback, you have to keep the parameters passed in Setup in sync with the type parameters used for Callback, and it has definitely caused me problems in the past. – Justin Holzer Feb 12 '20 at 18:44
49

Gamlor's answer worked for me, but I thought I would expand on John Carpenter's comment because I was looking for a solution involving more than one parameter. I figured other folks who stumble onto this page may be in a similar situation. I found this info in the Moq documentation.

I'll use Gamlor's example, but let's pretend the AsyncHandle method takes two arguments: a string and a SomeResponse object.

var mock = new Mock<Handler>();
string stringResult = string.Empty;
SomeResponse someResponse = null;
mock.Setup(h => h.AsyncHandle(It.IsAny<string>(), It.IsAny<SomeResponse>()))
    .Callback<string, SomeResponse>((s, r) => 
    {
        stringResult = s;
        someResponse = r;
    });

// do your test
new Foo(mock.Object).Bar(22);
Assert.AreEqual("expected string", stringResult);
Assert.IsNotNull(someResponse);

Basically you just need to add another It.IsAny<>() with the appropriate type, add another type to the Callback method, and change the lambda expression as appropriate.

JavaJudt
  • 787
  • 7
  • 8
35

The Callback method will certainly work, but if you are doing this on a method with a lot of parameters it can be a bit verbose. Here is something that I have used to remove some of the boilerplate.

var mock = new Mock<Handler>();

// do your test   
new Foo(mock.Object).Bar(22);

var arg = new ArgumentCaptor<SomeResponse>();
mock.Verify(h => h.AsyncHandle(arg.Capture()));
Assert.NotNull(arg.Value);

Here is the source for ArgumentCaptor:

public class ArgumentCaptor<T>
{
    public T Capture()
    {
        return It.Is<T>(t => SaveValue(t));
    }

    private bool SaveValue(T t)
    {
        Value = t;
        return true;
    }

    public T Value { get; private set; }
}
Andrew Radford
  • 3,227
  • 1
  • 20
  • 25
  • If you have multiple parameters, how do you get the second variable from arg.Value? – Shilan Nov 28 '20 at 07:28
  • If you have multiple parameters you can use multiple instances of ArgumentCaptor. If want to test the values from multiple invocations, you can use the Capture.In from one of the other answers. – Andrew Radford Nov 30 '20 at 22:51
22

Gamlor's answer works, but another way of doing it (and one which I consider to be more expressive in the test) is...

var mock = new Mock<Handler>();
var desiredParam = 47; // this is what you want to be passed to AsyncHandle
new Foo(mock.Object).Bar(22);
mock.Verify(h => h.AsyncHandle(desiredParam), Times.Once());

Verify is very powerful, and worth taking the time to get used to.

Pete Martin
  • 856
  • 7
  • 15
  • 18
    That approach is fine if you just want to check if a method got called with a known parameter. In the case where the parameter is not yet created at the point of writing the test (e.g. the unit in question creates the parameter internally), then Callback enables you to capture and interrogate this, whereas your approach wouldn't. – Mike Feb 25 '14 at 14:17
  • 1
    I need to store the passed value because I need to verify that all of a set of objects where passed. – MrFox Sep 26 '16 at 12:47
  • 1
    Also, sometimes the parameter is an entity, and you want separate asserts for each field in the entity. Best way to do that is to capture the param, rather than use Verify and a matcher. – Kevin Wong Apr 01 '20 at 21:08
11

You could use It.Is<TValue>() matcher.

var mock = new Mock<Handler>();
new Foo(mock.Object).Bar(22);
mock.Verify(h => h.AsyncHandle(It.Is<SomeResponse>(r => r != null )));
Ed Yablonsky
  • 119
  • 1
  • 5
  • Had a similar, but different scenario that this worked for. Was trying to test if a method was passed a (generated) Guid as a string. Was able to do `Guid tempGuid; mock.Verify(m => m.SomeMethod(It.Is(s => Guid.TryParse(s, out tempGuid)));` Perfect. – Mike Loux Sep 08 '21 at 16:47
8

This also works:

Mock<InterfaceThing> mockedObject = new Mock<InterfaceThing>();
var objectParameter = mockedObject.Invocations[1].Arguments[0] as ObjectParameter;
JJJ
  • 32,902
  • 20
  • 89
  • 102
Jeff Smith
  • 99
  • 1
  • 5
  • 2
    This is more elegant and convenient way to access mocked method parameters than in officially accepted answer, especially when you have more than one parameter. Also a `It.Is()` matcher mentioned by @Ed Yablonsky is very useful – Igor B Oct 24 '20 at 20:28
  • This is better than It.Is(), because you can separate parameter validation, so it's more atomic and you know what failed. – andrew.fox Sep 13 '22 at 10:02
3

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!

Jacob McKay
  • 2,776
  • 1
  • 19
  • 20
  • 1
    I like this. The Verify of Moq competes with the Assert of xUnit for the authority of performing asserts. That does not feel right on the Moq part of the setup. The It.Is feature setup should support non expressions too. – Thomas Dec 15 '19 at 09:33
  • "Moq competes with the Assert of xUnit for the authority of performing asserts" - Well said @Thomas. I would add that it would lose the competition. Moq is good at letting you know whether there was a matching call, but specific asserts give you much better information. The main drawback to my approach is losing the type safety and order checking of parameters. I've been looking for an improvement over this for a while, hopefully there's a C# ninja out there who can hack an example together! Otherwise if I find a way I will update this. – Jacob McKay Mar 19 '20 at 20:25
  • 1
    @JacobMcKay I tried myself on it and now you can specify the overload to use with a lamda expression and check multiple arguments that have the same type. The order on which the arguments with the same type are checked is used. Here you can find my modifications: [link](https://gist.github.com/Mrxx99/f7573c0103fb485d1daa89ab33251279). – Alex Dec 09 '20 at 18:39
  • @Alex that is cool! It's more Moq-ish with passing an expression, thanks for the fork! I'm still looking for an improvement over the looseness of matching assertions to arguments. I would love a callback method that gets passed the arguments with type safety that matches the expression, dunno if it's possible with C# – Jacob McKay Dec 11 '20 at 20:08