Exclude setup from verifying in Moq

September 29th 2023 Moq Unit Testing .NET

Mocking frameworks can be used not only to mock methods, but also to verify whether those mocked methods have actually been called. The latter is sometimes called interaction testing and is particularly useful when you want to test that specific calls to an external API have been called.

Of course, Moq also supports such setup verification:

[Test]
public void Method1ReturnsNonEmpty()
{
    mockDependency.Setup(x => x.Method1()).Returns("method 1");
    var service = new Service(mockDependency.Object);

    service.Method().Should().Be("method 1");

    mockDependency.Verify(x => x.Method1());
}

When setting up multiple mocked methods for a test case, it can become tedious to make sure that all the calls have been verified. In such cases, you can call VerifyAll instead:

[Test]
public void Method1ReturnsNonEmpty()
{
    mockDependency.Setup(x => x.Method1()).Returns("method 1");
    var service = new Service(mockDependency.Object);

    service.Method().Should().Be("method 1");

    mockDependency.VerifyAll();
}

Sometimes you might want to mock a method in a single place to be used in multiple tests, even if not all of them will actually call the method:

private Mock<IDependency> mockDependency;

[SetUp]
public void Setup()
{
    mockDependency = new Mock<IDependency>();
    mockDependency.Setup(x => x.Method2()).Returns("method 2");
}

[Test]
public void Method1ReturnsEmpty()
{
    mockDependency.Setup(x => x.Method1()).Returns("");
    var service = new Service(mockDependency.Object);

    service.Method().Should().Be("method 2");

    mockDependency.VerifyAll();
}

[Test]
public void Method1ReturnsNonEmpty()
{
    mockDependency.Setup(x => x.Method1()).Returns("method 1");
    var service = new Service(mockDependency.Object);

    service.Method().Should().Be("method 1");

    mockDependency.VerifyAll();
}

If you do this, you won't be able to use VerifyAll anymore, because any test that doesn't call the mocked method will fail:

Moq.MockException : Mock: This mock failed verification due to the following: IDependency x => x.Method2(): This setup was not matched.

For a long time, there was no easy way to handle such a case in Moq. You weren't able to use VerifyAll anymore, and had to explicitly verify all the mocked methods you were interested in. With version 4.20, this has changed. You can now define in more detail how you want to verify a specific mocked method. And one of the options is to only check how many times a method may be called at most. Such a definition can effectively disable the verification for a particular method:

mockDependency.Setup(x => x.Method2())
    .Returns("method 2")
    .Verifiable(Times.AtMost(int.MaxValue));

The same approach can be used even if you're using Moq.AutoMock in your tests:

private AutoMocker mocker;

[SetUp]
public void Setup()
{
    mocker = new AutoMocker();
    mocker.Setup<IDependency, string>(x => x.Method2())
        .Returns("method 2")
        .Verifiable(Times.AtMost(int.MaxValue));
}

[Test]
public void Method1ReturnsEmpty()
{
    mocker.Setup<IDependency, string>(x => x.Method1()).Returns("");
    var service = mocker.Get<Service>();

    service.Method().Should().Be("method 2");

    mocker.VerifyAll();
}

[Test]
public void Method1ReturnsNonEmpty()
{
    mocker.Setup<IDependency, string>(x => x.Method1()).Returns("method 1");
    var service = mocker.Get<Service>();

    service.Method().Should().Be("method 1");

    mocker.VerifyAll();
}

You can check how I use this new feature with and without Moq.AutoMock in my GitHub repository.

When writing interaction tests, the ability to verify calls of all mocked methods can immensely simplify test code. Unfortunately, this only works if you really want to verify the call to all mocked methods without exceptions. The new version of Moq adds a feature to exclude individual mocked methods from verifying while still being able to verify all the others with a single call.

Get notified when a new blog post is published (usually every Friday):

If you're looking for online one-on-one mentorship on a related topic, you can find me on Codementor.
If you need a team of experienced software engineers to help you with a project, contact us at Razum.
Copyright
Creative Commons License