Liberal Mocks
March 23, 2009
I've been using mock4as recently as part of a drive to get better test coverage in a flex project. As I used it I noticed a few features which I've seen in other mocking libraries that were missing. I did what any engineer with an itch to scratch might do in such a situation - I started to implementing the features in mock4as that I wanted to use.
One of the things I added was support for a pattern/feature which I'm going to refer to here as 'liberal mocks'. I am not really sure what the right name for this pattern is. I've seen it called 'null object' before, and also 'stubs'. In my opinion both those terms are too overloaded to be used in this context, although the Null Object pattern is very similar to what I'll be describing.
I definitely wouldn't use the word 'stub' in connection to this pattern, although I've seen that done in other mocking libraries. For a start there is already way too much confusion in automated testing between Stubs and Mocks. For the record, my definition of a Stub is pretty close to what's described in the XUnit Test Patterns book (which I highly recommend). It's a Test Double which is used to control indirect input into a system under test, and possibly to record indirect output for later verification. That second part is where my definition differs from Meszaros's - I merge Test Stub and Test Spy together. Anyway, I'd love to hear from anyone who has a better (or more 'correct') name for the pattern I'm describing.
On to the main attraction. A Liberal Mock is a mock which will not fail when it receives an unexpected method. Instead it will silently ignore the method call. Contrast this to a regular, or 'strict' mock. In most mocking libraries a standard mock which receives a method call that was not specified while the mock's expectations were being set will be considered an error, and the mock will not pass verification.
A couple of unit tests from the mock4as library's test suite should help to illustrate this:
Now, just because you can doesn't always mean you should. I've found that liberal mocks can be a bit of a crutch for a less-than-optimal design. If you find yourself needing to use a lot of liberal mocking then you should consider that to be a design smell. Maybe the method you're testing is doing too much work. If you can break your big method up into smaller methods that are testable then you're in a happier place, in terms of testing and more importantly in terms of design. Alternatively, the issue may be that the dependency which you're mocking out has some huge sprawling interface that should be split into several pieces. After doing that you may find that you only need to set expectations on one of those pieces, and the other parts can be replaced with a true Null Object.
One of the things I added was support for a pattern/feature which I'm going to refer to here as 'liberal mocks'. I am not really sure what the right name for this pattern is. I've seen it called 'null object' before, and also 'stubs'. In my opinion both those terms are too overloaded to be used in this context, although the Null Object pattern is very similar to what I'll be describing.
I definitely wouldn't use the word 'stub' in connection to this pattern, although I've seen that done in other mocking libraries. For a start there is already way too much confusion in automated testing between Stubs and Mocks. For the record, my definition of a Stub is pretty close to what's described in the XUnit Test Patterns book (which I highly recommend). It's a Test Double which is used to control indirect input into a system under test, and possibly to record indirect output for later verification. That second part is where my definition differs from Meszaros's - I merge Test Stub and Test Spy together. Anyway, I'd love to hear from anyone who has a better (or more 'correct') name for the pattern I'm describing.
On to the main attraction. A Liberal Mock is a mock which will not fail when it receives an unexpected method. Instead it will silently ignore the method call. Contrast this to a regular, or 'strict' mock. In most mocking libraries a standard mock which receives a method call that was not specified while the mock's expectations were being set will be considered an error, and the mock will not pass verification.
A couple of unit tests from the mock4as library's test suite should help to illustrate this:
public function testFailsIfUnexpectedMethodCalled():void { var mock:MockSomeInterface = new MockSomeInterface(); mock.doSomething(); assertFalse(mock.success()); } public function testSuccess_whenUnExpectedMethodCalledOnLiberalMock():void { var mock:MockSomeInterface = new MockSomeInterface(); mock.isLiberal(); mock.doSomething(); assertTrue(mock.errorMessage(), mock.success()); }That covers the what, now on to the why. The main scenario where I find myself reaching for liberal mocks is when I have a method which uses several features of a dependency, but I'm writing a test which is only interested in certain aspects of that usage. For example, let's say I have a controller object which is responsible for maintaining a view object. The controller has an initialize() method which sets the view's UI elements to some initial state, and I'd like to get that method under test. Now if the view has a lot of UI elements I wouldn't want to test all of the setup in one test. Instead I might want tests like initialize_shouldSetupCampaignDropDownCorrectly(), initialize_shouldSetupDaypartingViewWithModelContents(), etc. If I was mocking the view with a strict mock then every test would need to explicitly set expectations for all the calls which the controller will be making to the view, even if each individual test is only interested in a small subset of those calls. With liberal mocks that requirement is removed. I can essentially say 'this dependency is going to be used in a bunch of ways here, but I'm only concerned with these specific method calls'. The underlying motivation for this is to avoid Fragile Tests. If you're not using liberal mocks and one aspect of your expected behavior changes then suddenly all your tests will fail, not just the test that specifies the behavior that's just changed. Fragile tests seem to be a common risk for new automated testing practitioners, and they can be really demoralizing.
Now, just because you can doesn't always mean you should. I've found that liberal mocks can be a bit of a crutch for a less-than-optimal design. If you find yourself needing to use a lot of liberal mocking then you should consider that to be a design smell. Maybe the method you're testing is doing too much work. If you can break your big method up into smaller methods that are testable then you're in a happier place, in terms of testing and more importantly in terms of design. Alternatively, the issue may be that the dependency which you're mocking out has some huge sprawling interface that should be split into several pieces. After doing that you may find that you only need to set expectations on one of those pieces, and the other parts can be replaced with a true Null Object.