views:

37

answers:

2

When testing a class that uses a Moq dependency, I'd like the class to supply the arguments to a Moq method, rather than creating the arguments myself in the test case.

I have an interface, that has one method, which takes one argument.

public interface IMessageForwardProxy
{
    IMessage Send(IMessage request);
}

I have a class that calls this method with a number of different arguments depending on the method called on the class. For instance:

public class Messenger 
{
    private IMessageForwardProxy _link;

    public Messenger(IMessageForwardProxy proxy) { _link = proxy; }

    public bool DeliverSomeMessage() {
        IMessage m1 = new MessageOne();
        var response = _link.Send(m1);
        return response.Succeeded;
    }

    public bool DeliverSomeOtherMessage() {
        IMessage m2 = new MessageTwo();
        var response = _link.Send(m2);
        return response.Succeeded;
    }
}

Now as you can see, the Messenger class is responsible for creating the arguments that are passed to the Send method of the interface. When I'm testing this Messenger class, I would like to Mock the IMessageForwardProxy's Send method, without providing the argument in my tests. I see providing the argument as coupling my tests to the implementation (and duplicating work).

If I want to test the DeliverSomeOtherMessage method on the Messenger class, how would I mock the IMessageForwardProxy?

[Test]
public void TestDeliverSomeOtherMessage() {
    var mockProxy = new Mock<IMessageForwardProxy>();

    // This is what I want to avoid, since the method I'm testing creates this argument
    IMessage m2 = new MessageTwo(); 
    mockProxy.Setup(m => m.Send(m2)).Returns(new ReturnMessageTwo());

    // Can I do something like this instead? Define the signature, but not the param?
    mockProxy.Setup(m => m.Send(typeof(IMessage))).Returns(new ReturnMessageTwo());

    var messenger = new Messenger(mockProxy.Object);
    Assert.True(messenger.DeliverSomeOtherMessage());

}
+1  A: 

You can use It.IsAny<IMessage>()

Like this:

mockProxy.Setup(m => m.Send(It.IsAny<IMessage>())).Returns(new ReturnMessageTwo());
SelflessCoder
+1  A: 

In this case, you can use the It.Is<IMessage> expectation match:

mockProxy.Setup(m => m.Send(It.Is<IMessage>(m => m is MessageTwo)))
    .Returns(new ReturnMessageTwo());

This match is only true when the preducate passed to the It.Is method evaluates to true, so this Setup and corresponding return value will only be used when you invoke the DeliverSomeOtherMessage method.

Mark Seemann
Wouldn't that be the same as `It.IsAny<MessageTwo>()`?
SelflessCoder
@Jeff Cyr: No, because that would match a method with the signature Send(MessageTwo), and this method doesn't exist.
Mark Seemann