How To Write Unit Tests - Expected Value
Poorly written unit tests can pass for faulty code. Improperly asserting the expected value can be one of the reasons behind the false positives.
This article explains how to properly set expected value in unit tests.
Scenario
- Mutable Order class with setters
- Repository class that returns an Order from a Database
- Database interface is injected as a dependency to Repository and is of no further importance
- A unit test that checks if a correct Order was returned
Expected Not Properly Set
A commit to the code base changed the state of the Order object. The unit test is still passing, and the code went to Production.
Unit tests can pass when a given object instance is used as the expected object instance. That means that the expected object will contain all the changes applied to the given object.
Changes to the given object can happen inside a unit test, which is more obvious, or they can also happen inside the code being tested. The latter are difficult to spot.
Expected As a New Instance
The following unit test will not pass for faulty code.
This example relies on having an overridden equals method that matches all instance fields. Without it, the unit test would fail, since it will try to match object references instead. The Order has been converted from class to record, which automatically generated the equals method.
- Create a new instance for expected objects
- Do not change given or expected objects inside unit tests
- Do not write mutable classes
- Do not change object states after their creation, if a library contains mutable classes.
- The class being asserted should have the equals method overridden, which does not only check for reference equality
Full code samples can be found on GitHub.