Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested Moq verification

I am trying to figure out this Moq gymnastics for the last few hours. I have the following classes - and I am trying to do a somewhat simple verification and it's failing - and I can't seem to figure out why.

Notice during the Moq setup, I return a Mock.Of when BeginCounter is requested - but when I try to verify it it fails. However, if I uncomment the line p.Setup(e => e.BeginCounter.Increment()) the verify works.

What am I missing?

public interface IPerformanceCounters
{
    void Increment();
    void Decrement();
}

public interface IContext
{
    IPerformanceCounters BeginCounter { get; }
}

public class Test
{
    private readonly IContext context;
    public Test(IContext context) { this.context = context; }
    public void React() { this.context.BeginCounter.Increment(); }
}

void Test()
{
    // ARRANGE
    var p = new Mock<IContext>();
    p.Setup(e => e.BeginCounter).Returns(() => Mock.Of<IPerformanceCounters>());  // This does not work
    // p.Setup(e => e.BeginCounter.Increment()); // However, this works!

    // ACT
    var test = new Test(p.Object);
    test.React();

    // ASSERT
    p.Verify(v => v.BeginCounter.Increment(), Times.Once());
}
like image 837
splusq Avatar asked Nov 20 '12 01:11

splusq


1 Answers

I believe that this is because a non-setup method is not verifiable.

As far as I can tell, you are returning a mock and then trying to verify against it. But, it is not prepared until you uncomment the setup.

void Test()
{
    // ARRANGE
    var p = new Mock<IContext>();
    var perfCountMock = new Mock<IPerformanceCounters>();
    p.Setup(e => e.BeginCounter).Returns(() => perfCountMock.Object);  // This does not work
    perfCountMock.Setup(e => e.Increment());

    // ACT
    var test = new Test(p.Object);
    test.React();

    // ASSERT
    perfCountMock.Verify(v => v.Increment(), Times.Once());
}

The above is what you are really doing. You are not verifying the IContext call, but instead the IPerformanceCounters call. I would set it up this way so that it is easier to understand, but you could just as easily uncomment the line

If you want to leave it as is, you need to better understand the Mock.Of functionality.

void Test()
{
        // ARRANGE
        var p = new Mock<IContext>();
        var mockOfPerf = Mock.Of<IPerformanceCounters>();
        p.Setup(e => e.BeginCounter).Returns(mockOfPerf);  // This does not work

        // ACT
        var test = new Test1(p.Object);
        test.React();

                    // ASSERT
        Mock.Get(mockOfPerf).Verify(v=>v.Increment(), Times.Once());
}

This is the same thing as above, just using the intended functionality of Mock.Of. You cannot verify nested mocks, you need to verify against the actual mock

like image 169
Justin Pihony Avatar answered Sep 27 '22 21:09

Justin Pihony