Should I test that?

Should I test abstract classes?

Verdict

Yes

Test the concrete methods of an abstract class once, through a small subclass that exists only in the test, and test each real subclass for the methods it implements.

Why

Write one or two tests for the code that an abstract class implements, through a small subclass that exists only in the test. The typical case is an abstract base class in a web application with one shared method that three subclasses inherit. Blast radius is users because the shared method runs in every subclass, and Change frequency is rarely because a base class changes a few times a year. Detectability is same-day, since several features break at once and users report them, and Reversibility is trivial because a revert undoes the damage. Test cost is trivial because a stub subclass takes minutes to write, and rule R12 gives Test minimally.

When the decision changes
WhenDecisionWhy
The abstract class declares only abstract methods and has no method bodiesDo not test; the compiler checks that every subclass implements the abstract methodsDetectability drops to immediately, because a subclass that misses a method does not compile
A shared method in the abstract class calculates the fees that customers are chargedTest mandatory, including rounding and boundary amountsBlast radius rises to money and Reversibility to costly, because a wrong charge leads to refunds
The abstract class ships in a library that other teams subclassTest the shared methods, and publish a contract test that each subclass can runDetectability drops to eventually and Reversibility to with-effort: other teams find the bug after an upgrade
New hooks land in the abstract class every week as new subclasses appearTest the main path and each hook that the abstract class callsChange frequency rises to constantly
A test subclass needs a database or a framework container to start, and the integration tests of the real subclasses assert on the full output of the shared method, header line includedDo not test the abstract class alone; the integration tests of the real subclasses cover its codeTest cost rises to moderate; Detectability stays same-day because those assertions fail when the shared method breaks
The abstract class is part of a throwaway prototype that only you runDo not test; look at the output after each changeBlast radius drops to none
A concrete method's result depends on the value that a real subclass's hook returns, such as a total built from per-plan ratesTest: call the concrete method on each real subclassDetectability moves to eventually: the test subclass runs only its own hook, and a real hook that breaks the method's assumptions returns a plausible result

What breaks if you don't test

Take ReportExporter, a base class whose export() method writes a header row and then the rows that each subclass returns. A refactor moves the header into a helper and drops the line break after it. Every export now glues the first data row onto the header. Customers see a broken first column in their spreadsheets and report it the same day. No subclass test fails, because each one checks only the rows its subclass returns.

What you lose if you over-test

The common over-test repeats the assertions about the base class in the test of every subclass. With three subclasses, one header change means edits in three test files that check one line. A second over-test checks that each abstract method exists, which the compiler already enforces.

How to test

Test the shared behaviour once, at unit level. Declare a minimal subclass in the test file that returns a fixed value from each abstract method, and assert on the concrete method's result. One main-path test is the minimum; add a regression test for each bug in the base class. Test each real subclass for the methods it implements. When the concrete method's result depends on a real hook's value, also call the concrete method on each real subclass, because the stub runs only its own hook. In Java, Mockito builds the subclass with mock(ReportExporter.class, CALLS_REAL_METHODS).

When the answer changes

  • A shared method calculates an amount that customers pay.
  • Other teams subclass the base class from your library.
  • New hooks land in the base class every week.

Code example

One stub instead of three copies

This test covers export() once:

abstract class ReportExporter {
    String export() {
        return header() + "\n" + String.join("\n", rows());
    }
    String header() { return "id,name,created"; }
    protected abstract List<String> rows();
}

class ReportExporterTest {
    static class Stub extends ReportExporter {
        protected List<String> rows() { return List.of("1,Ada,2026-09-01"); }
    }

    @Test
    void writesHeaderLineBeforeRows() {
        assertEquals("id,name,created\n1,Ada,2026-09-01", new Stub().export());
    }
}

The Stub class has no logic of its own, so the test fails only when export() or header() is wrong. The order, customer and product exporter tests then check only their own rows().

FAQ

Should you unit test abstract classes?

Yes, test the methods that an abstract class implements, with one or two tests through a small test subclass. The abstract method declarations need no test, because the compiler rejects a subclass that misses one, and Python raises a TypeError when you instantiate it.

Should I unit test my subclasses or my abstract parent class?

Test both, each for its own code: the parent's concrete methods once through a test subclass, and each real subclass for the methods it implements. Repeating the parent's assertions in every subclass test adds an edit per subclass whenever the parent changes and finds no extra bugs. When a parent method's result depends on a subclass's hook, also call that parent method on each real subclass.

How do I test an abstract class in Java?

Declare a small static subclass in the test class that returns fixed values from the abstract methods, then call the concrete method and assert on its result. Mockito can generate the same subclass with mock(MyClass.class, CALLS_REAL_METHODS), which runs the real concrete methods.

Should I test abstract methods?

No, an abstract method has no body, so it holds no code that can fail. Test its implementation in each subclass instead.