Growing Object-Oriented Software, Guided By Tests (chapter 24)
Feb 27, 22We need to ensure that tests are not brittle (i.e too tied to production code). This will make the system and test suite harder to change, which is what we are trying to avoid!
Here are some things to avoid:
- Tests too tightly coupled to production code
- Tests overspecify the expected behaviour of the target code.
- Multiple tests exercise the same part of the production code (duplication).
Test brittleness is not just indicative of a disorganised test suite, it can also point to an issue with your design.
The main thing when writing tests is this:
### Specify precisely what should happen and no more
Tests should be written in terms of messages passed between objects.
Extract values into name constants.
Use precise assertions:
- Focus only on what is relevant to the scenario being tested.
- Avoid asserting behaviour that isn’t driven by the test inputs.
- Do not reassert behaviour that is covered in other tests.
Test behaviour, not methods!
If testing for equality of complex types, just assert on the specific fields required. Trying to do Obj1 == TestObj
will couple your test and production code.
If testing strings consider just testing that the string contains certain information. This will be more flexible, especially if the format/structure of the string could change.
If we find we are testing a lot of strings for equality, perhaps this behaviour could be extracted to a separate object and tested in isolation.
If there is a behaviour exhibited from peer objects in tests, do not assert on it! This will tightly couple your tests.
Here is a good tip:
Allow queries, expect commands
e.g queries should always return the same information so we can mock/stub these. We should expect that commands can return different results based on the state of the system.
We should ignore irrelevant objects in tests - just make sure they are specifically tested elsewhere!
Try to avoid specifying an invocation order in tests unless it is necessary.
Try to use ‘guinea pig objects’ that stand in as peer domain objects in tests. These objects should mimic the behaviour of the object without being coupled to it. Essentially, we want to try and extricate as much of the coupling as possible.