Moq and access to called parameters

I just started to implement unit tests (using xUnit and Moq) according to my already created project. The project makes heavy use of dependency injection through container units.

I have two services A and B. Service A is the one that is being tested in this case. Service A calls B and gives it a delegate for the internal function. This “callback” is used to notify A when a message is received that it should process.

Therefore, A calls (where b is an instance of service B):

b.RegisterHandler(Guid id, Action<byte[]> messageHandler);

In order to check Service A, I need to call messageHandler, as this is the only way it currently receives messages.

Can this be done with Moq? i.e. Can I laugh at service B so that when I call, the RegisterHandlervalue is messageHandlerpassed to my test?

Or do I need to reverse engineer this? Are there any design patterns I should use in this case? Does anyone know of any good resources for such a design?

+5
source share
2 answers

You can get an instance of a callback (or any other input parameter) using the callback method (the affinity name is random) in Mock:

[TestMethod]
public void Test19()
{
    Action<byte[]> callback = null;

    var bSpy = new Mock<IServiceB>();
    bSpy.Setup(b => b.RegisterHandler(It.IsAny<Guid>(), It.IsAny<Action<byte[]>>()))
        .Callback((Guid g, Action<byte[]> a) => callback = a);

    var sut = new ServiceA(bSpy.Object);
    sut.RegisterCallback();

    Assert.AreEqual(sut.Do, callback);
}

This works when ServiceA is defined as follows:

public class ServiceA
{
    private readonly IServiceB b;

    public ServiceA(IServiceB b)
    {
        if (b == null)
        {
            throw new ArgumentNullException("b");
        }

        this.b = b;
    }

    public void RegisterCallback()
    {
        this.b.RegisterHandler(Guid.NewGuid(), this.Do);
    }

    public void Do(byte[] bytes)
    {
    }
}
+9
source

, Moq . Visual Studio Unit Test...

[TestMethod]
public void MyTest()
    {
      var moqObject = new Mock<ServiceB>();

      // Setup the mock object to throw an exception if a certain value is passed to it...
      moqObject.Setup(b => b.RegisterHandle(unexpectedValue).Throws(new ArgumentException());

      // Or, setup the mock object to expect a certain method call...
      moqObject.Setup(b => b.RegisterHandle(expectedValue));

      var serviceA = new ServiceA(moqObject.Object);

      serviceA.DoSomethingToTest();

      // This will throw an exception if an expected operation didn't happen...
      moqObject.VerifyAll();
    }
0

All Articles