views:

199

answers:

2

Example:

public bool Save(MyObj instance)
{
    if (instance.IsNew)
    {
        this.repository.Create(instance);
    }
    else
    {
        this.repository.Update(instance);
    }
}

How do I create a test in Moq that verifies:

  1. that a property IsNew is being read
  2. that either Create() or Update() has been invoked
+1  A: 

Off the top of my head: Verifying that the IsNew property is being read:

var mock = new Mock<MyObj>();
mock.Setup(m => m.IsNew).Returns(true).Verifiable();
//...
sut.Save(mock.Object);
//...
mock.Verify();

In the example above, the IsNew property will return true, so the Create path will be taken.

To verify that either the Create or Update method was invoked, you need to have some hook into that functionality. It looks like Repository is a static class, in which case you can't replace it with a Test Double, but I may be reading your code in the wrong way... If you can replace it with a Test Double (Mock), you can use the same principle as outlined above.

If you can examine the state of your Repository after the Save method has been called, you may be able to tell by State-Based Testing which of the two code paths were followed.

If there's no externally observable difference between the result of the two code paths, it's probably a better idea not to test this specific implementation detail. It might lead you towards an anti-pattern called Overspecified Test - you can read more about this anti-pattern and many other unit test-related things in the excellent book xUnit Test Patterns.


Edit: Testing the repositories can be done in the same way:

var myObjMock = new Mock<MyObj>();
myObjMock.Setup(m => m.IsNew).Returns(true);

var repositoryMock = new Mock<Repository>();
repositoryMock.Setup(m => m.Create(myObjMock.Object)).Verifiable();

var sut = new SomeClass(repositoryMock.Object);
sut.Save(myObjMock.Object);

repositoryMock.Verify();

The call to Verifiable is the key. Without it, the default behavior of Moq is to get out of the way, do the best it can and not throw any exceptions if at all possible.

When you call Verifiable, you instruct the mock to expect that particular behavior. If that expectation has not been met when you call Verify, it will throw an exception, and thus fail the test.

Mark Seemann
I changed code for my repository. This was just code. It wasn't meant to be Singleton Repository. Actually I have an interface, so I can inject my repository at my objet instantiation (constructor overload).
Robert Koritnik
I added Verifiable() inside my test. But there's no difference when expectation's not met. I always get the same exception.
Robert Koritnik
A: 

Unfortunately I have a solution myself.

All you have to do is to have a local int variable that you set to 0 and then mocking increments it. In the end you have to check whether its name is more than 0 (or exactly 1, depending on the problem).

// Arrange
int count = 0;
Mock<Repository> mock = new Mock<Repository>();
mock.Setup<bool>(m => m.Create(It.IsAny<MyObj>())).Callback(() => count++);
mock.Setup<bool>(m => m.Update(It.IsAny<MyObj>())).Callback(() => count++);
// Act
...
// Assert
Assert.AreEqual(count, 1);

There would be two tests. One that sets property IsNew to true and one that sets it to false.

Robert Koritnik
See my updated answer below. In general, you should try to express expectations as explicitly as possible. With Moq, this can be effectively accomplished using the Verifiable and Verify methods. That would be more explicit. For regular users of Moq, that would also be what they would expect, so a test written in that way would be more legible than your solution.
Mark Seemann
Havent used Verifiable before. Great. I'll try and see the difference.
Robert Koritnik