Reputation: 105071
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:
IsNew
is being readCreate()
or Update()
has been invokedUpvotes: 3
Views: 3226
Reputation: 105071
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
.
Upvotes: 3
Reputation: 233367
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.
Upvotes: 3