Moq - passing arguments from setup() to returns()

Viewed 1749

I am not sure how to pass arguments from Setup() to Returns() in Moq.

Here is an example:

public static IInterfaceHandler GetInterfaceHandlerMoq()
{
   // Defining the moq
   var moq = new Mock<IInterfaceHandler>();

   // Trying to set up a moq using another moq
   moq.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid>(), It.IsAny<string>()))
       .Returns((Guid guid, string value) => GetProgrammerMoq(guid, value));

   // Return mocked object
   return moq.Object;
}

Note that GetProgrammerMoq() is a library that will return another Moq. Here is the code:

public static IProgrammer GetProgrammerMoq(Guid guid, string instName)
{
    // Create Moq
    var moq = new Mock<IProgrammer>();

    // Set up the returnables
    moq.Setup(o => o.InstanceName).Returns(programmer + "_" + instName);
    moq.Setup(o => o.Guid).Returns(guid);

    // Return mocked object
    return moq.Object;
}

See here that GetProgrammerMoq() needs its arguments to be set up based on what is passed to CreateCommunicationInterface().

My test then tries to get and use the Moq, but "p" is returned as null (because, I guess, my arguments are not passed properly to Returns()).
Here is a draft of what the test is to look like:

[Fact]
public void DoSomething()
{
    IInterfaceHandler test = ProgrammerMoqs.GetInterfaceHandlerMoq();

    Guid? g = new Guid();
    IProgrammer p = test.CreateCommunicationInterface(g, "test-boff");

    ...
}
1 Answers

Try this:

   var moq = new Mock<IInterfaceHandler>(MockBehavior.Strict);

MockBehavior.Strict: if you get NULLs from Mock, then always try MockBehavior.Strict. When some setup is not prepared, Moq by default returns NULL. But with MockBehavior.Strict, it will throw an exception. Every single attempt to call anything from the mock object, if it lacks proper setup, will throw.

If you get an exception when trying MockBehavior.Strict, then it means that the:

.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid>(), It.IsAny<string>()))

failed to catch the invocatio, so the mock returned NULL by default.

Why did it fail to catch the invocation? There are several options:

  • CreateCommunicationInterface may be overloaded and your setup matched another overload that you did not expect
  • filters (It.IsAny..) didn't match the actual arguments
  • (..)

Klaus Gütter noted in the comments about the difference of Guid and Guid?. In fact, the filter you are using is It.IsAny() while in the test you pass:

Guid? g = new Guid();

g is not an object of type Guid, it's Nullable<Guid>, hence the filter looking for any-Guid did not match. The code compiled, because the result of the expression It.IsAny<Guid>() fits Guid? wanted by the method, but still the types don't match.

If you try It.IsAny<Guid?>() it will probably match fine and return what you wanted.

moq.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid?>(), It.IsAny<string>()))
   .Returns((Guid? guid, string value) => GetProgrammerMoq(guid, value));
Related