There are two ways of testing the workings of a class:
- State based testing or result- driven testing (state verification) determines if the executed method works correctly by examining the state of the system under test and its collaborators (dependencies)
- Interaction testing or action-driven testing - tests how a method sends / receives input from another method
State based testing is preferable to interaction testing.
So, we have to test only one thing per test, meaning that there can be only one “Class Under Test“. But objects of different types collaborate within an application, so we have to use Mock objects for all those which are not the Class under Test. These fake objects decide whether the unit test has failed or not, by testing whether the Object under Test has interacted as expected with the Mock object.
There should be only one mock object per test.
The differences between stubs and mock objects:
| Stubs | Mock objects |
| make tests run smoothly | checks interactions between objects |
| cannot fail tests (or should not |
can fail tests |
| replace objects so we can test the others without problems | used to test if a test has failed or not |
| no asserts can be done on stubs | asserts should be done on mock objects, and not other objects; they record (are affected) by the communication with the object under test |
Mocks and stubs can be combined (example at page 92).
Both mocks and stubs should be reusable (therefore we don’t write tests within them).
Mocks and stubs are grouped under the term Fakes. The same class can be both a mock or a stub, depending on how it is used.
Best practices:
- One test (method for testing) – one thing tested.
- (Pattern for naming a test method function test_whatMethod_entryValues_expectedResult() - so that the dev know right away what is being tested, if the test fails)
- One test means one mock object only, the other objects in the test being stubs, if not the Class under Test.
- good to know for complex tests – you only have to ask yourself “”What is the mock object here?” and things should become clearer.
- A powerful technique is using stub chains - stubs that return other stubs or other mocks
Because handwriting mocks and stubs takes a lot of time, is difficult, cumbersome, makes tests hard to maintain and reuse and also means adding more tests to the system (the tests for the handwritten stubs), there are Isolation frameworks (mock object frameworks) to help. They remove repetitive coding, making tests more readable and easier to implement. (ex.: C++/mockpp, Java /Jmock, Java /EasyMock, .NET – NMock, Moq, Typemock Isolator, Rhyno Mocks)