Verdict
No
Do not repeat the tests of an inherited method in every subclass; test the method once in the class that defines it, and test each subclass only for the methods it adds or overrides.
Why
- Blast radiususers
- Change frequencyrarely
- Detectabilityimmediately
- Reversibilitytrivial
- Test costmoderate
Do not repeat the tests of an inherited method in every subclass; test the method once in the class that defines it. The typical case is a subclass in your own application that inherits a method unchanged from a base class with its own tests. Blast radius is users, because a broken method shows wrong output in every subclass, and Change frequency is rarely, because a base class changes a few times a year. Detectability is immediately and Reversibility is trivial: the base class tests fail in CI and the change never merges. Test cost is moderate, because every subclass carries a copy of the assertions that needs an edit when the base method changes, and rule R8 gives Do not test.
| When | Decision | Why |
|---|---|---|
| The subclass overrides a hook that the inherited method calls | Test: call the inherited method on the subclass for each overridden hook | Detectability moves to eventually, because the base class tests run only the base hook; Test cost falls to trivial |
| Other code handles every subclass through the base type, and a new subclass arrives every month | Test: run the base class tests against every subclass through an abstract test class | Change frequency rises to regularly and Detectability moves to eventually; Test cost falls to trivial |
| The inherited method calculates the fee that customers pay | Test mandatory, with boundary amounts, in the base class and in every subclass that overrides a hook of the fee method | Blast radius rises to money and Reversibility to costly, because a wrong charge leads to refunds |
| The base class that defines the inherited method has no tests | Test minimally: one test of the method, written once for the base class | Detectability drops to same-day, because users report the bug; Test cost falls to trivial for one test |
| The method is inherited from a framework class, such as save() on a Django model | Do not test the framework's method; test your code that uses it | The framework limit for code that you do not own applies, and Detectability stays immediately: the framework's own tests fail when the method breaks |
What breaks if you don't test
Manager inherits getEmail() from Employee unchanged. A bug in getEmail() fails the Employee tests, so a copied Manager test adds nothing. The failure that slips through needs a subclass that changes what the inherited method reads. A Contractor subclass overrides domain(), which getEmail() calls, and returns agency instead of agency.example.com, so every contractor address bounces. The Employee tests stay green, and nobody notices until a contractor asks about a missing onboarding email weeks later.
What you lose if you over-test
With Employee, Manager and Contractor, copied tests turn one change to the email format into edits in three test files that check the same line of production code. A bug in the base method then fails three tests, and the report points at the subclasses instead of the class that holds the bug.
What to do instead
Test each method at unit level in the class that defines it, and in each subclass test cover only what the subclass adds or overrides. When a subclass overrides a hook that an inherited method calls, call the inherited method on the subclass and assert on the result. When other code handles every subclass through the base type, write the base class tests once in an abstract test class with a factory method, and let each subclass test extend it. The JUnit user guide shows this pattern with test interfaces and default methods, and the Java tutorial on overriding covers which methods a subclass replaces.
Procedure and references
When the answer changes
- A subclass overrides a hook that an inherited method calls.
- Other code treats every subclass as the base type, and new subclasses keep arriving.
- The inherited method calculates an amount that customers pay.
Counterexample + Code example
The override that changed an inherited method
The advice to skip inherited methods fails in the template method pattern, where the base method calls a hook that a subclass overrides. The inherited code has no new line, but in the subclass it runs through an override that no base class test reaches. Detectability moves to eventually and Test cost falls to trivial, so the framework gives Test:
class Export {
String fileName() { return slug() + "." + extension(); }
String slug() { return "report-2026-09"; }
String extension() { return "csv"; }
}
class PdfExport extends Export {
@Override
String extension() { return ".pdf"; } // bug: leading dot
}
class PdfExportTest {
@Test
void inheritedFileNameUsesPdfExtension() {
assertEquals("report-2026-09.pdf", new PdfExport().fileName());
}
}
A test of extension() alone passes, because ".pdf" is what the author meant. Only the test of the inherited fileName() fails, and it shows report-2026-09..pdf.
Related questions
FAQ
- Should I unit test methods which are inherited from a superclass?
No, test an inherited method once, in the tests of the superclass that defines it. Test it again through the subclass only when the subclass overrides a method that the inherited method calls, since the superclass tests never run that override.
- Should I test the base class or the subclasses?
Test both, each for its own code: the base class for the methods it defines, and each subclass for the methods it adds or overrides. A method that a subclass inherits unchanged needs no second test.
- How do I run the same tests against every subclass?
Write the base class tests in an abstract test class with an abstract factory method, and give each subclass a test class that extends it and implements the factory. JUnit 5 supports the same pattern with a test interface whose default methods hold the tests.
- Should I test methods inherited from a framework class?
No, the framework's maintainers test inherited methods such as
save()on a Django model. Test your own code that overrides them, for example a customsave()that fills in a slug.