Having a chat with a colleague the other, brought up the issue of strict mocks. I commented that strict mocks should be used sparingly and only in certain circumstance, and this led to a series of discussions on why that is.
Strict and loose Mocks
Usually mocking frameworks provide two types of mocks: strict and loose. If you're using RhinoMocks, these are called StrictMock and DynamicMock. If you're using Moq, you set the behaviour (Loose = Dynamic = Default or Strict) in the mock creation.
RhinoMock has a static mock repository that you can use to create mocks, called MockRepository. This saves you on having to explicitly create a mock repository. Thus, instead of doing:
you could write this:
Using the static repository, you cannot pick between dynamic and strict mocks. All mocks are dynamic. This somehow promotes the usage of dynamic mocks over strict ones.
With Moq, as with RhinoMocks, the default behaviour is of loose mocks. Thus, writing:
is equivalent to:
which in turn is the same as:
If you want to use strict mocks:
(Note that with Moq, to access the actual Mocked object, you need to access the .Object property. RhinoMocks doesn't require this because it uses extension methods).
Using Strict Mocks
So, now that we know how to create the two different types of mocks depending on the framework, let's take a look at a SUT and see where the problem with strict mocks lie. To make the post shorter, I'll use RhinoMocks, but you can accomplish the same with Moq.
Suppose we have the following class:
and we want to test that when calling ServiceClass.FirstMethod, the corresponding call Dependency.FirstMethod is called, we could be tempted to do something like the following:
We've verified that Dependency.FirstMethod is called, everything passes, all is fine.
Welcome to BrittleVille
Two days later we get a change of request, that requires us to adjust the code for ServiceClass.FirstMethod. In particular, we need to call Dependency.ThirdMethod:
We check in the changes, run our tests, and boom! Test failed:
XunitException: Rhino.Mocks.Exceptions.ExpectationViolationException : IDependency.ThirdMethod(); Expected #0, Actual #1.
With strict mocks EVERY single call to the mocked object has to have expectations set on it. If we make an additional call and we don't set the expectation, our test will fail. Our test was to verify the FirstMethod was being called, and it still is. Our test failed because we wrote it using strict mocks, it failed for the wrong reason, and made our code very brittle.
However, if we were to have written the test using Dynamic mocks, this wouldn't happen:
Note that out test is still valid. If we remove the call to Dependency.FirstMethod the test will fail as it should. However, it won't fail if we add additional calls.
An added bonus to using loose mocks with RhinoMocks, is that you can use the AAA (Arrange-Act-Assert) syntax and also call individual expectations. Thus the previous code could be written like so:
Alternatively, if you don't need expectations to return values, you can just call AssertWasCalled on them:
Mocks are a great thing to test behaviour between different components. However, make sure you use them correctly if you don't want to end up with brittle code that any minor change breaks a whole bunch of tests. Strict and ordered mocking should only be used in exceptional cases.