Skip to content

28 · 32 · 5 min

Testing behaviour, not structure

Object oriented code hides state behind behaviour, which is good design and makes a specific testing mistake tempting: reaching for the state anyway.

Test through the public interface

java
@Test
void withdrawal_beyond_balance_is_rejected() {
    var account = new Account("A-1", 1000);

    assertThrows(InsufficientFunds.class, () -> account.withdraw(1500));
    assertEquals(1000, account.balance());
}

This asserts a rule the class promises. It survives any rewrite of the internals, which is the property that makes a test worth keeping.

A test that reads private fields by reflection, or that exists only because a method was made public to allow testing, is testing structure. It fails when you refactor and passes when you break behaviour, which is the change detector problem from the software engineering course.

Arrange, act, assert

java
@Test
void discount_applies_above_the_threshold() {
    var order = new Order();                  // arrange
    order.add(new Item("book", 600));

    var total = order.totalWith(new BulkDiscount(500, 10));   // act

    assertEquals(540, total);                 // assert
}

One act per test. Two actions in one test means a failure does not say which one broke.

The name is the specification

discount_applies_above_the_threshold tells you what broke from the report alone. testOrder3 requires opening the file. Listing the test names of a class should read as its contract.

What makes a class hard to test

Difficulty testing is a design signal, not a testing problem:

SymptomDesign cause
Needs a database to constructdependencies built internally
Needs eight arguments to set upthe class does too much
Assertions on time are flakythe clock is not injected
Must call three methods in order firstleaking internal sequencing
Only testable through the UIlogic living in the wrong layer

Each row is fixed by changing the class, not by writing a cleverer test.

What not to test

Getters and setters that do nothing. Framework behaviour. Third party libraries. Private methods directly, which are exercised through the public ones that use them.

Testing trivia inflates the count and the coverage number and catches nothing, and the tests still have to be maintained.