1. Overview

An enum is a special type of class that extends the Enum class. It consists of a group of static final values, which makes them unchangeable. Furthermore, we use enums to define a set of expected values one variable could hold. This way, we make our code more readable and less error-prone.

However, when it comes to testing, we’d like to mock enum values in some scenarios. In this tutorial, we’ll learn how to mock an enum using the Mockito library and discuss the situations where this might be useful.

2. Dependency Setup

Before we dive in, let’s add the mockito-core dependency to our project:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.13.0</version>
    <scope>test</scope>
</dependency>

It’s important to note that we need to use dependency version 5.0.0 or higher to be able to mock the static methods.

For older Mockito versions, we’d need to add the additional mockito-inline dependency in our pom.xml:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>5.2.0</version>
    <scope>test</scope>
</dependency>

We don’t need to add the mockito-inline for higher versions since it’s incorporated in the mockito-core.

3. Example Setup

Next, let’s create a simple Direction enum we’ll use throughout this tutorial:

public enum Direction {
    NORTH,
    EAST,
    SOUTH,
    WEST;
}

In addition, let’s define a utility method that uses a previously created enum and returns a description based on the passed value:

public static String getDescription(Direction direction) {
    return switch (direction) {
        case NORTH -> "You're headed north.";
        case EAST -> "You're headed east.";
        case SOUTH -> "You're headed south.";
        case WEST -> "You're headed west.";
        default -> throw new IllegalArgumentException();
    };
}

4. Solution With Mocking an Enum

To examine the application’s behavior, we could use already defined enum values in test cases. However, in some scenarios, we’d like to mock an enum and use a value that doesn’t exist. Let’s address a few.

One of the examples we’d need such a mock would be ensuring the values we might add to the enum in the future wouldn’t result in unexpected behavior. Another example would be aiming for a high percentage of code coverage.

Now, let’s create a test and mock an enum:

@Test
void givenMockedDirection_whenGetDescription_thenThrowException() {
    try (MockedStatic<Direction> directionMock = Mockito.mockStatic(Direction.class)) {
        Direction unsupported = Mockito.mock(Direction.class);
        Mockito.doReturn(4).when(unsupported).ordinal();

        directionMock.when(Direction::values)
          .thenReturn(new Direction[] { Direction.NORTH, Direction.EAST, Direction.SOUTH,
            Direction.WEST, unsupported });

        assertThrows(IllegalArgumentException.class, () -> DirectionUtils.getDescription(unsupported));
    }
}

Here, we used the mockStatic() method to mock invocations to static method calls. This method returns a MockedStatic object for the Direction type. Next, we defined a new mocked enum value and specified what should happen when we call the ordinal() method. Lastly, we included the mocked value in the result the values() method returns.

As a result, the getDescription() method throws the IllegalArgumentException for the unsupported value.

5. Solution Without Mocking an Enum

Moving forward, let’s examine how to achieve the same behavior, but this time without mocking an enum.

First, let’s define the Direction enum in the test directory and add the new UNKNOWN value:

public enum Direction {
    NORTH,
    EAST,
    SOUTH,
    WEST,
    UNKNOWN;
}

The newly created Direction enum should have the same path as the enum we previously defined in the source directory.

Furthermore, since we defined the enum with the same fully qualified name as the one from the source directory when test cases execute, they’ll use the one provided in the test sources directory.

Also, since we defined the enum with the same fully qualified name as the one from the source directory, the Direction enum under the sources directory will be overloaded with the one provided in the test directory. Therefore, the test engine uses the one provided in the test directory.

Let’s test the behavior of the getDescription() method when the UNKNOWN value is passed:

@Test
void givenUnknownDirection_whenGetDescription_thenThrowException() {
    assertThrows(IllegalArgumentException.class, () -> DirectionUtils.getDescription(Direction.UNKNOWN));
}

As expected, the call on the getDescription() method throws the IllegalArgumentException exception.

One of the possible drawbacks of using this approach is that now we have the enum that isn’t part of our source code, and, additionally, it affects all tests in our test suite.

6. Conclusion

In this article, we learned how to mock an enum using the Mockito library. We also examined a few scenarios where this might be useful.

To sum up, mocking an enum can be helpful when we want to test whether our code would behave expectedly if we introduce a new value. We also learned how to do the same by overloading the existing enum instead of mocking its values.

As always, the entire code used in this article can be found over on GitHub.