I know, it's tough to test for impossible situations. Especially testing the default case of your switch :) like this one.
switch (animal) { case: CAT: // do cat stuff break; case: DOG: // do dog stuff break; default: throw new IllegalArgumentException("Dunno what to do"); }
Imagine someone introduces a new enum that's not handled and forgets to add a new case.
Unfortunately Mockito does not allow creating a mock for enum, so here comes Powermock. I'm not a big fan of mocks and especially those that mock static methods, I think it's a bad smell. However mocking enums for testing illegal or default cases is just that single spot where it makes sense.
So to begin with let's add these dependencies to our project:
<powermock.version>2.0.9</powermock.version> ..... <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency>
Then we need to mock enum before the test class is loaded. It's a bit tricky and involves messing with JDK internals. Different JDK versions have different names for enum values constant within the Enum class.
@BeforeClass public static void prepareEnum() { int optionsLength = Animal.values().length; Animal[] newAnimals = new Animal[optionsLength + 1]; System.arraycopy(Animal.values(), 0, newAnimals, 0, optionsLength); strangeAnimal = PowerMockito.mock(Animal.class); Whitebox.setInternalState(strangeAnimal, "name", Integer.toString(optionsLength)); Whitebox.setInternalState(strangeAnimal, "ordinal", optionsLength); newAnimals[optionsLength] = strangeAnimal; try { // works in eclipse Whitebox.setInternalState(Animal.class, "ENUM$VALUES", newAnimals); } catch (Exception e) { // some JDK's put these in different field Whitebox.setInternalState(Animal.class, "$VALUES", newAnimals); } }
In the code above we create a mock enum with the help of bytecode manipulation and then replace values array in our enum class (in order for the switch to work correctly). Different JDK's have different name for this array. Maybe your will have yet another one :)
You might also want to write separate test classes for "regular" enum values and the illegal one, since if you only test normal cases in the "powered" unit tests the normal enum class will have zero coverage (after all Jacoco will see reference to the generated class).
Here's the link to a Github project with this exercise.