Last updated: 2026-10-26
Testing Object Behaviour
Part of Object Orientation as the Beginning of Software Engineering, picking up the equipment-loan example where it left EquipmentItem.
A test is a claim: given this starting state and this action, the object's observable behaviour will be exactly this. Writing the claim down next to the class it is about, while the class's own rules are still fresh, is what turns "I think this works" into something a reader โ or a later version of you โ can check without re-reading the implementation.
Tests Written With the Class Applied / MethodologicalKnowledge with a 5โ10 year half-life โ stable practice
The examples below use JUnit 5, the version most current Java tooling defaults to1.
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class EquipmentItemTest {
@Test
void newItemIsAvailable() {
EquipmentItem item = new EquipmentItem("VR-014", "VR headset");
assertTrue(item.isAvailable());
}
@Test
void itemCannotBeLentTwice() {
EquipmentItem item = new EquipmentItem("VR-014", "VR headset");
item.lendTo(new Borrower("s123"));
assertThrows(
IllegalStateException.class,
() -> item.lendTo(new Borrower("s456")));
}
@Test
void blankAssetIdIsRejected() {
assertThrows(
IllegalArgumentException.class,
() -> new EquipmentItem(" ", "VR headset"));
}
}
Three small things to notice. The test names say what is being claimed, not what method is being called โ itemCannotBeLentTwice reads as a sentence about behaviour, which is the point of the name, not the fact that it happens to invoke lendTo twice. Two of the three tests are negative paths: they exist to show that an invalid operation is refused, not that a valid one succeeds, and a suite that only ever tests the happy path has quietly tested less than half of what the class promises. And every one of these tests was written while EquipmentItem's constructor and lendTo method were still being decided โ the test is what lets you change the implementation later and know, in seconds, whether the promise still holds.
A Test That Proves Almost Nothing Applied / MethodologicalKnowledge with a 5โ10 year half-life โ stable practice
@Test
void testEquipmentItem() {
EquipmentItem item = new EquipmentItem("VR-014", "VR headset");
assertNotNull(item);
}
This compiles, runs, and passes โ and it is weak evidence, because new EquipmentItem(...) either throws or returns a non-null object; there is no third outcome for assertNotNull to usefully rule out. A test's value is measured by what it would have caught if the class were wrong, not by whether it currently passes. Line coverage tools will happily report this line as "covered" without telling you that nothing about it was actually tested.
Tests can also do something more useful than confirm a class works: they can expose that it was drawn in the wrong place to begin with. A method that needs five collaborating objects constructed just to call one line is a class with too many responsibilities telling you so before a reviewer has to.
Worth Investigating Further Applied / MethodologicalKnowledge with a 5โ10 year half-life โ stable practice
Each of these already has a full treatment elsewhere on this site โ they are signalled here, not re-explained, because the point in this module is recognising when one would help, not mastering all of them at once.
- TDD/BDD โ writing the test before the code it describes, rather than after.
- Testing Fundamentals โ the vocabulary (unit, integration, system) this page's single-class tests are one instance of.
- Types of Testing, including
@ParameterizedTestand boundary-value testing โ the natural next step once a class takes more than one or two kinds of input worth checking separately. - Mutation Testing โ a way of testing your tests, by deliberately breaking the class and checking whether anything notices.
- Test Doubles: Mocks, Stubs, Fakes โ what to do once a class depends on something slow, external, or not yet built, such as
LoanRepositoryin the main page's example.
Independent-learning lead. Property-based testing โ generating many inputs from a rule rather than writing each case by hand โ is a further step past parameterised tests, worth a look once hand-written cases start to feel repetitive.
Related Topics
- Object Orientation as the Beginning of Software Engineering โ the hub page this one continues from, including the
EquipmentItemclass these tests cover. - Objects in a Codebase โ what a commit history and a README add once tests exist alongside the code.
- Testing Fundamentals โ the broader vocabulary this page's examples sit inside.
References
JUnit Team. JUnit 5 User Guide (version 5.14.2). https://docs.junit.org/5.14.2/user-guide/ โฉ