Reset mock verification in Moq?

C#Unit TestingMoq

C# Problem Overview


Setup as so:

public interface IFoo
{
    void Fizz();
}

[Test]
public void A()
{
    var foo = new Mock<IFoo>(MockBehavior.Loose);

    foo.Object.Fizz();

    foo.Verify(x => x.Fizz());

    // stuff here

    foo.Verify(x => x.Fizz(), Times.Never()); // currently this fails
}

Basically I'd like to enter some code at the // stuff here to make the foo.Verify(x => x.Fizz(), Times.Never()) pass.

And because this probably constitutes moq/unit testing abuse, my justification is so I can do something like this:

[Test]
public void Justification()
{
    var foo = new Mock<IFoo>(MockBehavior.Loose);
    foo.Setup(x => x.Fizz());

    var objectUnderTest = new ObjectUnderTest(foo.Object);

    objectUnderTest.DoStuffToPushIntoState1(); // this is various lines of code and setup

    foo.Verify(x => x.Fizz());

    // reset the verification here

    objectUnderTest.DoStuffToPushIntoState2(); // more lines of code

    foo.Verify(x => x.Fizz(), Times.Never());
}

Basically, I have a state object where a fair bit of work (both in terms of making various mock objects and other faffing around) is requires to push it into State1. Then I want to test the transition from State1 to State2. Instead of duplicating or abstracting the code I'd prefer to just re-use the State1 test, push it into State2 and perform my Asserts - all of which I can do except the verification calls.

C# Solutions


Solution 1 - C#

This is now supported in Moq

Use .Invocations.Clear() on the latest version of the library:

var foo = new Mock<foo>();
foo.Invocations.Clear();

Old answer

I think long after this post was created they added the functionality that the OP had asked for, there is a Moq extension method called Moq.MockExtensions.ResetCalls().

With this method you can do exactly what you wished as shown below:

[Test]
public void Justification()
{
    var foo = new Mock<IFoo>(MockBehavior.Loose);
    foo.Setup(x => x.Fizz());

    var objectUnderTest = new ObjectUnderTest(foo.Object);

    objectUnderTest.DoStuffToPushIntoState1(); // this is various lines of code and setup

    foo.Verify(x => x.Fizz());

    foo.ResetCalls(); // *** Reset the verification here with this glorious method ***

    objectUnderTest.DoStuffToPushIntoState2(); // more lines of code

    foo.Verify(x => x.Fizz(), Times.Never());
}

Solution 2 - C#

I don't think you can reset a mock like this. Instead, if you know that Fizz should be called once when transitioning to state 1, you can do your verifies like this:

objectUnderTest.DoStuffToPushIntoState1();
foo.Verify(x => x.Fizz(), Times.Once());  // or however many times you expect it to be called

objectUnderTest.DoStuffToPushIntoState2();
foo.Verify(x => x.Fizz(), Times.Once());

Having said that, I would still create two separate tests for this. As two tests, it's easier to see whether the transition into state 1 is failing, or the transition into state 2 is failing. Additionally, when tested together like this, if your transition into state 1 fails, the test method exits and your transition into state 2 doesn't get tested.

Edit

As an example of this, I tested the following code with xUnit:

[Fact]
public void Test()
{
    var foo = new Mock<IFoo>(MockBehavior.Loose);

    foo.Object.Fizz();
    foo.Verify(x => x.Fizz(), Times.Once(), "Failed After State 1");
            
    // stuff here
    foo.Object.Fizz();
    foo.Verify(x => x.Fizz(), Times.Once(), "Failed after State 2"); 
}

This test fails with the message, "Failed after State 2". This simulates what would happen if your method that pushes foo into State 2 calls Fizz. If it does, the second Verify will fail.

Looking at your code again, since you are calling one method to verify it does/does not call another method on the mock, I think you need to set CallBase to true so that the base DoStuffToPushIntoState2 is called rather than the mock's override.

Solution 3 - C#

Addition to answer by @stackunderflow (haha, nice nick :))

In later versions of Moq, Moq.MockExtensions.ResetCalls() was marked as obsolete. mock.Invocations.Clear() should be used instead:

foo.Invocations.Clear();

Solution 4 - C#

I have also witnessed the Times.Exactly(1) verification failure across unit tests using MoQ, with a "was called 2 times" error message. I see this as a bug in MoQ, as I would expect clean mock states on every test run.

My work around was to assign a new mock instance and test target in the test setup.

private Mock<IEntityMapper> entityMapperMock;
private OverdraftReportMapper target;

[SetUp]
public void TestSetUp()
{
  entityMapperMock = new Mock<IEntityMapper>();
  target = new OverdraftReportMapper(entityMapperMock.Object);
} 

Solution 5 - C#

Depends on which version of Mock you use, I know for sure we can do this

someMockObject.ResetCalls();

Solution 6 - C#

This is indeed unit test abuse as you are verifying two things in one test. Your life would be much easier if you took the ObjectUnderTest initialisation out of the test and into a common setup method. Then your tests become much more readable and independant of each other.

More than production code, test code should be optimized for readability and isolation. A test for one aspect of system's behavior should not affect other aspects. It really is much much easier to refactor common code into a setup method than to try to reset the mock objects.

ObjectUnderTest _objectUnderTest;

[Setup] //Gets run before each test
public void Setup() {
    var foo = new Mock<IFoo>(); //moq by default creates loose mocks
    _objectUnderTest = new ObjectUnderTest(foo.Object);
}
[Test]
public void DoStuffToPushIntoState1ShouldCallFizz() {
    _objectUnderTest.DoStuffToPushIntoState1(); // this is various lines of code and setup

    foo.Verify(x => x.Fizz());
}
[Test]
public void DoStuffToPushIntoState2ShouldntCallFizz() {
{
    objectUnderTest.DoStuffToPushIntoState2(); // more lines of code
    foo.Verify(x => x.Fizz(), Times.Never());
}

Solution 7 - C#

You could use the Callback method instead of Verify, and count the calls.

This is demonstrated on the Moq Quick Start page, thus:

// returning different values on each invocation
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThing())
    .Returns(() => calls)
    .Callback(() => calls++);
// returns 0 on first invocation, 1 on the next, and so on
Console.WriteLine(mock.Object.GetCountThing());

Solution 8 - C#

Next approach works fine for me (using Moq.Sequence)

    public void Justification()
    {
        var foo = new Mock<IFoo>(MockBehavior.Loose);
        foo.Setup(x => x.Fizz());

        var objectUnderTest = new ObjectUnderTest(foo.Object);

        objectUnderTest.DoStuffToPushIntoState1(); // this is various lines of code and setup

        foo.Verify(x => x.Fizz());

        // Some cool stuff
        
        using (Sequence.Create())
        {
            foo.Setup(x => x.Fizz()).InSequence(Times.Never())
            objectUnderTest.DoStuffToPushIntoState2(); // more lines of code
        }
    }

Let me know if it worked out for you

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionfostandyView Question on Stackoverflow
Solution 1 - C#stackunderflowView Answer on Stackoverflow
Solution 2 - C#Jeff OgataView Answer on Stackoverflow
Solution 3 - C#CodeFullerView Answer on Stackoverflow
Solution 4 - C#Henrik VoldbyView Answer on Stackoverflow
Solution 5 - C#AustinTXView Answer on Stackoverflow
Solution 6 - C#Igor ZevakaView Answer on Stackoverflow
Solution 7 - C#Ed HarlingView Answer on Stackoverflow
Solution 8 - C#ArtiomView Answer on Stackoverflow