15

This seems like something simple but I can't seem to get it to work.

I have a class with a Save method that simply calls another method ShouldBeCalled(). I want to verify that if I call Save() that the other method ShouldBeCalled() is executed at least once. I thought that I could do the following.

public class ClassA
{
    public virtual void Save()
    {
        ShouldBeCalled();
    }

    public virtual void ShouldBeCalled()
    {
        //This should get executed
    }
}

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_Should_Call_ShouldBeCalled()
    {
        var mockClassA = new Mock<ClassA>();
        mockClassA.Object.Save();

        mockClassA.Verify(x => x.ShouldBeCalled(), Times.AtLeastOnce());
    }
}

But I get the exception "Expected invocation on the mock at least once, but was never performed: x => x.ShouldBeCalled()"

It is just a guess but Is Moq overriding the Save() method with it's own version which ignores anything I have inside the real object's Save() method.

Adam
  • 1,561
  • 2
  • 15
  • 25

4 Answers4

29

You are having this problem because you are mocking what you are testing. This doesn't make sense.

You are correct that Moq will replace the implementation of your method with its own. The reason is you are supposed to use Moq to mock things the class you are testing calls, not the class you are testing itself.

This test would be appropriate if your code were designed thusly:

public class ClassA
{
    BusinessLogicClass bl;
    public ClassA(BusinessLogicClass bl)
    {
         this.bl = bl;
    }

    public void Save()
    {
        bl.ShouldBeCalled();
    }
}

public class BusinessLogicClass
{
    public virtual void ShouldBeCalled()
    {
        //This should get executed
    }
}

And here is the correct test of that method now:

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_ShouldCallShouldBeCalled()
    {
        //Arrange
        var mockBLClass = new Mock<BusinessLogicClass>();
        mockBLClass.Setup(x => x.ShouldBeCalled()).Verifyable();

        //Act    
        ClassA classA = new ClassA(mockBLClass.Object);
        classA.Save();

        //Assert
        mockBLClass.VerifyAll();
    }
}

The key lesson here is that you mock/stub what your test needs to run, not what you are testing itself.

Hope this helps, Anderson

Anderson Imes
  • 25,500
  • 4
  • 67
  • 82
  • 1
    +1: Great answer, complete with breaking out the dependency and code examples! Note that an alternative to the virtual method would be to add an IBusinessLogic interface and pass that in. – TrueWill Sep 13 '09 at 18:09
  • The IBusinessLogic interface is definitely the way to go here, but I didn't want to get too deep into it. – Anderson Imes Sep 13 '09 at 18:14
  • 1
    Thanks for the great answer. I had a feeling I was trying to do something wrong with my approach and now I know I was :) – Adam Sep 13 '09 at 20:23
  • You should use AAA and put a Verify at the end to replace the Setup and VerifyAll see http://stackoverflow.com/questions/980554/what-is-the-purpose-of-verifiable-in-moq/1728496#1728496 – Ruben Bartelink Nov 13 '09 at 10:59
  • I am implicitly doing arrange act assert and I don't really see how one is better than the other, given the scope of this mock. Were I reusing mocks that would be another thing entirely, but I'm not. – Anderson Imes Nov 13 '09 at 15:47
  • Also, I'm not really sure why you downvoted me... I answered the OP's question and set him straight. – Anderson Imes Nov 13 '09 at 16:51
  • I don't think this answers the question. The question was asking how (using Moq) you can verify that the object under test called another method within the same class. The answer splits the class into two separate classes in order to mock/stub the class with the method in question. This avoids the question in my mind. – jhsowter Jun 25 '13 at 10:40
  • @jhowter - This is entirely true, but the value of such a test is minor and generally considered an antipattern. It's one of the rare cases on SO where I allowed myself to divert into "don't do that" land, which I generally find annoying as well. I didn't answer the question... you are correct. I feel fine about it, but if you disagree and that the true answer has value, the answer by Eric answers it correctly: http://stackoverflow.com/a/7897345/3244 – Anderson Imes Aug 20 '13 at 02:53
  • @AndersonImes You're right that it's an antipattern and if someone wrote that code at work I would give them (my version of) your answer. However, there may be reasons why sometimes CallBase might be needed - presumably that's why Moq included it in their framework. Adding tests to legacy code is one example which springs to mind. – jhsowter Apr 25 '14 at 14:20
  • In fact it's only really an anti-pattern when writing UNIT tests. For integration tests, we are allowed to "mock" behaviour of external code and that's what we can do by using CallBase. – jhsowter Apr 25 '14 at 14:22
  • 1
    @jhsowter again you are correct and this is good for folks to know. I don't like the design of Moq's CallBase because there are situations where you might forget to set it back when using persistent mocks across tests. I'd prefer to continue encouraging people to look at the testability of their design, rather than how a mocking library can get around poorly thought out tests. I recognize the "legacy" usecase (a reason one might even consider a more powerful isolation framework like TypeMock or PowerMock), but unless the OP specifies that limitation I'd err on the side of "doing it right". – Anderson Imes Apr 27 '14 at 18:01
5

Try using the CallBase = true and then false. I ran your code and it works.

var mockClassA = new Mock<ClassA>();
mockClassA.CallBase = true;
mockClassA.Object.Save();
mockClassA.CallBase = false;
mockClassA.Verify(x => x.ShouldBeCalled(), Times.AtLeastOnce());
Eric Rohlfs
  • 1,811
  • 2
  • 19
  • 29
  • This does work, wow! I'm new to Moq so have no idea if this is good practice or not, but it works. Note that this only works if you're mocking a concrete class with virtual methods, as is the case with ClassA. If the class implements an interface and you create the mock from the interface this won't work. eg If ClassA implemented IClassA then the first line of Eric's answer would change to "var mockClassA = new Mock();" Mocking the interface in this way the test will fail as ShouldBeCalled is never called. Very similar problem to the original code in Adam's question. – Simon Elms Apr 19 '13 at 00:42
2

Yes, this can be done. However, you need to add a line of code to have Moq track whether or not the ShouldBeCalled method was indeed called.

Something like the following will work:

var mockClassA = new Mock<ClassA>();
mockClassA.Setup(x => x.ShouldBeCalled()).Verifiable();    
mockClassA.Object.Save();    
mockClassA.Verify(x => s.ShouldBeCalled(), Times.AtLeastOnce());

The Setup method sets up expectations. When you call Verify, you are asking Moq to verify these expectations. If you don't make a Setup call to create expectations for the ShouldBeCalled method, then Moq doesn't consider it to be trackable and will therefore fail hard when you try to Verify it.

David Andres
  • 31,351
  • 7
  • 46
  • 36
  • I tried the above but I'm still seeing the same error. What you are saying make sense that's why I can't figure out why it isn't working. – Adam Sep 13 '09 at 15:46
  • Can you change the Setup declaration to mock a return? For example, mockClassA.Setup(x => x.ShouldBeCalled()).Returns(...). – David Andres Sep 13 '09 at 15:58
  • The setup is redundant here as you're not using Strict. But +1 in general – Ruben Bartelink Nov 13 '09 at 10:59
  • I, too, get the same error Adam reported. I'm curious, has anyone got this code to work? The reason I ask is that I assume the Save method being called here is generated in the mock, and does not use the Save method implementation in ClassA. Therefore I would expect it NOT to call the ShouldBeCalled method. – Simon Elms Apr 19 '13 at 00:29
1

You can stub methods in the system under test using CallBase.

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_Should_Call_ShouldBeCalled()
    {
        // Arrange
        var mockClassA = new Mock<ClassA>();
        mockClassA.CallBase = true; // this will call real methods unless the method is mocked/stubbed. 
        mockClassA.Setup(a => a.ShouldBeCalled());

        // Act
        mockClassA.Save();

        // Assert
        mockClassA.Verify(a => a.ShouldBeCalled(), Times.Once());
    }
}
jhsowter
  • 619
  • 3
  • 8