Should I test that?

Should I test enums?

Verdict

No

Do not write unit tests for an enum that only lists constants stored by name; let exhaustive switches make the compiler reject a new constant, and test the code that uses the enum.

Why

Do not write unit tests for an enum that only lists constants. For the typical case, an OrderStatus enum stored and serialized by name and read in switch expressions, Blast radius is users and Change frequency is rarely: a wrong status reaches an order page, and the enum gains a constant a few times a year. Detectability is immediately, because the compiler rejects a removed constant, and an exhaustive switch rejects a new constant with no branch. Reversibility and Test cost are both trivial. Rule R8 gives Do not test.

When the decision changes
WhenDecisionWhy
The database column stores the enum's ordinal, as JPA does for `@Enumerated` without `EnumType.STRING`Test: one test that fails when a stored constant changes positionDetectability moves to eventually and Reversibility to costly: an inserted constant changes the meaning of stored rows
The enum's constants carry behaviour, such as a method that returns the next order statusTest: one case per constant for each methodDetectability moves to eventually and Reversibility to with-effort: a wrong transition leaves orders for a script to repair
Code switches over the enum with a `default` branch, or in a language with no exhaustiveness checkTest: one parameterized test that runs the switch for every constantDetectability moves to eventually and Reversibility to with-effort: a new constant silently takes the default path
Installed mobile apps or a partner service read the enum's names as JSON stringsTest minimally: one serialization test that asserts the string for each constantDetectability moves to eventually, Reversibility to with-effort and Test cost to moderate: only old client versions see a renamed constant
Each constant of the enum carries the price that checkout charges for a planTest mandatory: assert the charged amount for each constantBlast radius rises to money, Detectability moves to eventually and Reversibility to costly: wrong charges are refunded by hand
The enum lists user roles, and each constant carries the permissions it grantsTest mandatory: one allowed case and one denied case per roleBlast radius rises to safety-or-legal, Detectability moves to never and Reversibility to impossible: an overbroad role silently exposes other customers' records

What breaks if you don't test

For an enum that only lists constants, nothing breaks that the compiler misses: assertEquals("PAID", OrderStatus.PAID.name()) checks a fact that Java guarantees. The failures sit in the code around the enum. A switch statement with a default branch sends a new CANCELLED constant down the wrong path, and cancelled orders show "Paid" until someone notices days later.

What you lose if you over-test

A test that asserts the name of every constant copies the enum into a second file. Each new constant then needs two edits, and the test fails only when someone changes the enum on purpose. The coverage report marks the enum as tested, while the switch that mishandles a new constant stays unchecked.

What to do instead

Let the compiler check the switches. In Java, read the enum in switch expressions, which must cover every constant, as JEP 361 specifies, and leave out the default branch so that a new constant fails the build. In TypeScript, assign the value to never in the default case, as the TypeScript handbook on exhaustiveness checking shows. Store the enum in the database by name with @Enumerated(EnumType.STRING). Then test the behaviour that reads the enum: the order page, the status transition, the invoice.

When the answer changes

  • Database rows hold the constant's ordinal, or clients that you do not ship read its name.
  • Constants gain fields or methods, such as a price, a list of permissions, or a next-status rule.
  • Code switches over the enum with a default branch, or in a language with no exhaustiveness check.

Code example + Counterexample

The constant added in the middle

The usual advice, that an enum needs no test, is wrong for this one:

public enum OrderStatus { PENDING, CANCELLED, PAID, SHIPPED }

@Entity
class Order {
    @Enumerated // no EnumType given: JPA stores the ordinal
    OrderStatus status;
}

class OrderStatusStorageTest {
    // Rows in the orders table already hold 0, 1 and 2.
    // New constants go at the end.
    @Test
    void storedOrdinalsKeepTheirMeaning() {
        assertEquals(List.of(PENDING, PAID, SHIPPED),
            List.of(OrderStatus.values()).subList(0, 3)); // fails
    }
}

A developer inserts CANCELLED after PENDING to keep lifecycle order. Every stored 1 now loads as CANCELLED instead of PAID, and nothing crashes, so Detectability moves to eventually. Rows written before and after the deploy hold the same numbers with different meanings, so Reversibility moves to costly, and the framework returns Test. The Jakarta Persistence documentation for @Enumerated states that ORDINAL is the default, so the lasting fix is EnumType.STRING plus a migration of the column.

FAQ

Should one test the values of an enum using unit tests?

No, a unit test that asserts the names of an enum's constants restates the declaration. Test the code that reads the enum instead, and let exhaustive switch expressions make the compiler reject a new constant. Test enum values only when database rows store the ordinal or clients that you do not ship read the names.

Should I test all enum values in a contract?

Yes, when a mobile app or a partner service reads an enum as JSON strings, add one serialization test that asserts the string for every constant. A renamed constant compiles in your own code, so only clients on old versions see the change.

Should I test enum methods?

Yes, test a method on an enum like any other method with logic, with one case per constant. A wrong next-status method leaves orders in the wrong state without a crash.

How do I test every value of an enum in JUnit?

Use @EnumSource(OrderStatus.class) on a parameterized test, which runs the test once per constant, as the JUnit guide to parameterized tests describes. Point the test at code that switches over the enum, so a new constant without a branch fails CI.