tags:

views:

353

answers:

2

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.

+1  A: 

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
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
Can you change the Setup declaration to mock a return? For example, mockClassA.Setup(x => x.ShouldBeCalled()).Returns(...).
David Andres
The setup is redundant here as you're not using Strict. But +1 in general
Ruben Bartelink
+6  A: 

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
+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
The IBusinessLogic interface is definitely the way to go here, but I didn't want to get too deep into it.
Anderson Imes
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
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
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
Also, I'm not really sure why you downvoted me... I answered the OP's question and set him straight.
Anderson Imes