Should I test that?

Should I test inherited methods?

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

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 the decision changes
WhenDecisionWhy
The subclass overrides a hook that the inherited method callsTest: call the inherited method on the subclass for each overridden hookDetectability 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 monthTest: run the base class tests against every subclass through an abstract test classChange frequency rises to regularly and Detectability moves to eventually; Test cost falls to trivial
The inherited method calculates the fee that customers payTest mandatory, with boundary amounts, in the base class and in every subclass that overrides a hook of the fee methodBlast 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 testsTest minimally: one test of the method, written once for the base classDetectability 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 modelDo not test the framework's method; test your code that uses itThe 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.

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.

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 custom save() that fills in a slug.