The aim of unit tests is to verify that units (typically, methods) behave according to their specification. This is supposed to bring the following benefits:
- verification of correctness (including edge-cases)
- API smoke-testing (if a method is hard to test, it's probably hard to use)
- enabling re-factoring
Since unit tests are supposed to verify a specification, good unit tests involve good documentation of the tested APIs.
Writing good unit tests
Good unit tests have the following properties:
- they are contradictable, i.e. they actually verify something which can be coerced to fail
- they do not depend on the implementation details of the method being tested
- they run quickly
Ideally, unit tests should have the following structure:
- Given ...
- When ...
- Then ...
The tests start by setting up the necessary context (which may involve mocking), before invoking the tested method (with no mocking), and finally verifying the method's results or effects.