Mocking Java enum to add a value to test fail case Mocking Java enum to add a value to test fail case java java

Mocking Java enum to add a value to test fail case


Here is a complete example.

The code is almost like your original (just simplified better test validation):

public enum MyEnum {A, B}public class Bar {    public int foo(MyEnum value) {        switch (value) {            case A: return 1;            case B: return 2;        }        throw new IllegalArgumentException("Do not know how to handle " + value);    }}

And here is the unit test with full code coverage, the test works with Powermock (1.4.10), Mockito (1.8.5) and JUnit (4.8.2):

@RunWith(PowerMockRunner.class)public class BarTest {    private Bar bar;    @Before    public void createBar() {        bar = new Bar();    }    @Test(expected = IllegalArgumentException.class)    @PrepareForTest(MyEnum.class)    public void unknownValueShouldThrowException() throws Exception {        MyEnum C = mock(MyEnum.class);        when(C.ordinal()).thenReturn(2);        PowerMockito.mockStatic(MyEnum.class);        PowerMockito.when(MyEnum.values()).thenReturn(new MyEnum[]{MyEnum.A, MyEnum.B, C});        bar.foo(C);    }    @Test    public void AShouldReturn1() {        assertEquals(1, bar.foo(MyEnum.A));    }    @Test    public void BShouldReturn2() {        assertEquals(2, bar.foo(MyEnum.B));    }}

Result:

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.628 sec


If you can use Maven as your build system, you can use a much simpler approach. Just define the same enum with an additional constant in your test classpath.

Let's say you have your enum declared under the sources directory (src/main/java) like this:

package my.package;public enum MyEnum {    A,    B}

Now you declare the exact same enum in the test sources directory (src/test/java) like this:

package my.packagepublic enum MyEnum {    A,    B,    C}

The tests see the testclass path with the "overloaded" enum and you can test your code with the "C" enum constant. You should see your IllegalArgumentException then.

Tested under windows with maven 3.5.2, AdoptOpenJDK 11.0.3 and IntelliJ IDEA 2019.3.1


Rather than using some radical bytecode manipulation to enable a test to hit the last line in foo, I would remove it and rely on static code analysis instead. For example, IntelliJ IDEA has the "Enum switch statement that misses case" code inspection, which would produce a warning for the foo method if it lacked a case.