Verdict
No
Do not write tests for getters and setters that only return or assign a field; test the code that uses the values.
Why
- Blast radiususers
- Change frequencyrarely
- Detectabilityimmediately
- Reversibilitytrivial
- Test costtrivial
Do not write tests for getters and setters that only return or assign a field. For the typical case, accessors on a domain class generated by the IDE, Lombok, or the language, the factors are: Blast radius is users, Change frequency is rarely, Detectability is immediately, Reversibility is trivial, and Test cost is trivial. Detectability is immediately because an accessor has no logic of its own: the compiler rejects a renamed field, and the tests of the code that reads the value fail in the same CI run. Reversibility is trivial because a revert fixes a wrong accessor and leaves no data behind. Rule R8 gives Do not test, but the case sits on the edge: an accessor that holds logic moves the decision to a test.
| When | Decision | Why |
|---|---|---|
| The setter validates its input, for example it rejects a negative quantity | Test: one valid value and one test per rejection rule | Detectability moves to eventually and Reversibility to with-effort: a broken check stores bad values silently |
| The getter computes an amount that customers pay, such as an order total after discounts | Test mandatory, including boundary amounts | Blast radius rises to money, Reversibility to costly and Detectability to eventually |
| The getter returns an internal mutable list that callers can change | Test that changing the returned list leaves the object unchanged | Detectability moves to never and Reversibility to with-effort: callers corrupt the object's state silently |
| A JSON library serialises the class through its getters for a client that another team ships | Test minimally: one serialisation test that asserts the field names | Detectability moves to eventually, Reversibility to with-effort and Test cost to moderate: renaming a getter renames the JSON field |
| The accessors are written by hand and several fields share one type | Test: one round-trip assertion per field, until the accessors are generated | Detectability moves to eventually: a copy-paste slip returns a plausible value of the right type |
What breaks if you don't test
For a generated accessor, nothing breaks that your other checks miss. A getter that returns the wrong field makes the code that reads it misbehave, and the tests of that code fail in CI. The failures that reach users come from accessors with logic: a setter that trims an email, a getter that adds tax, a getter that hands out its internal list. Those are methods in everything but name, and the conditions table covers them.
What you lose if you over-test
A DTO with 20 fields has 40 accessors. A round-trip test per field adds 20 tests that repeat the field list, so every new field needs a test edit and every rename touches two files. The tests never fail on their own, because a generated accessor cannot drift from its field. Under a coverage gate, accessor tests are the cheapest lines to cover, so they fill the quota that should point at untested logic.
What to do instead
Generate the accessors so there is no hand-written body to get wrong: Lombok @Getter and @Setter, Java records, C# auto-properties, or Kotlin properties. Test the behaviour that uses the values: the calculation, the serialised response, the rendered page. For Java setters that are still written by hand, turn on Error Prone, whose SelfAssignment check fails the build on x = x. The Lombok getter and setter guide shows the annotations and their options.
When the answer changes
- An accessor gains a line beyond the return or the assignment, such as a range check or a unit conversion.
- A JSON library or an ORM reads the class by accessor names, and a client you do not ship depends on those names.
- Accessors are typed by hand in a codebase without generation or static analysis.
Code example
The setter that assigned to itself
This hand-written setter compiles with plain javac and never stores anything:
public class Customer {
private String email;
public void setEmail(String email) {
email = email; // assigns the parameter to itself; the field stays null
}
public String getEmail() { return email; }
}
@Test
void setEmailStoresTheValue() {
Customer c = new Customer();
c.setEmail("ana@example.com");
assertEquals("ana@example.com", c.getEmail());
}
The round-trip test catches this bug. Error Prone's SelfAssignment check catches it in every setter of the codebase at compile time. A setter generated by Lombok or the IDE writes this.email = email and cannot contain the bug. On a 20-field class, one compiler check replaces 20 round-trip tests.
Related questions
FAQ
- Should you unit test getters and setters?
No, getters and setters that only return or assign a field need no unit tests of their own. Test the behaviour that uses the values, and generate the accessors so there is no hand-written body to get wrong. A getter or setter that validates or computes gets tests, because it holds logic that can fail silently.
- Should unit tests be written for getters and setters?
No, unit tests for plain getters and setters cost upkeep and never fail, because generated accessors cannot drift from their fields. Test the code that calls the accessor instead. A getter or setter with logic, such as validation or a computed total, gets unit tests like any other method.
- How do I exclude generated getters from code coverage?
With Lombok and JaCoCo, set
lombok.addLombokGeneratedAnnotation = trueinlombok.config. JaCoCo 0.8.2 and later leaves out every class and method annotated with an annotation namedGenerated. Accessors with hand-written logic stay in the report.- Should I test a setter that validates its input?
Yes, test a setter that validates input with one valid value and one test per rejection rule. Without those tests, a broken check stores invalid values silently, and repairing them takes a data script.
- Should I test Java record accessors?
No, the Java compiler generates record accessors from the record components, so there is no body to test. Test the compact constructor if it validates the components.