Skip to content

.Verify() on one mock complains over missing invocations on another mock #1699

Description

@JeppeSN

(I know this is really a kind of duplicate of #1018, but since I am not authorized to comment on the closed issue, I am communicating it here.)

We had a test that was written like below (here simplified). Essentially the same as #1018 (hence the namespace), but in this case the "extra" .Setup is there for a legitimate reason. Here written without the use of MockRepository.

Steps to Reproduce

This full console app (C#) illustrates the situation:

using Moq;

namespace Moq1018;

static class Program {
    static void Main() {
        // set up all
        var mockOne = new Mock<IOne>(MockBehavior.Strict);
        var mockTwo = new Mock<ITwo>(MockBehavior.Strict);
        mockOne.Setup(x => x.GetSomething()).Returns(mockTwo.Object).Verifiable();
        mockTwo.Setup(x => x.DoSomething()).Verifiable();

        // make SUT
        var objectToTest = new ObjectToTest(mockOne.Object);

        // call first method and verify
        objectToTest.FirstMethod();
        mockOne.Verify();

        // call second method and verify
        objectToTest.SecondMethod();
        mockTwo.Verify();
    }
}

class ObjectToTest(IOne one) {
    ITwo? _Member;

    public void FirstMethod() {
        _Member = one.GetSomething();
    }

    public void SecondMethod() {
        _Member?.DoSomething();
    }
}

public interface IOne {
    ITwo GetSomething();
}
public interface ITwo {
    void DoSomething();
}

Expected Behavior

It feels the above test (just called Main here) should complete without failure.

Actual Behavior

When control reaches mockOne.Verify(), an exception is thrown because the setup on mockTwo has not been met (yet)!

Known Workarounds

  1. If we change overload of .Returns and write .Returns(() => mockTwo.Object) instead of simply .Returns(mockTwo.Object), then it works as expected. Saw this workaround in MockRepository.Verify() also verifies mocks created outside of the repo #1018, but it feels unnatural that this change should lead to another outcome.
  2. If we move the mockTwo.Setup statement several lines down, to after the mockOne.Verify call, then the code runs without issue. This may give clearer test code in some cases, but above, the author wanted to keep all setups together in a single "section" of the test method.
  3. If we move the mockOne.Verify() down to after the call to objectToTest.SecondMethod(), then it works. But then we cannot really prove if it was FirstMethod() or SecondMethod() that did GetSomething.
  4. Maybe there is an entirely different way to write the test that I had not thought of?

Version Info

Moq 4.20.72

Back this issue
Back this issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions