In certain situations it may be desirable to test the default
case of a switch
statement even if at the current time all possible values of the enum are covered (e.g. in case in the future a new value is added and not covered in the switch statement). Whether or not this does always make sense is debatable but not the concern of this post.
To achieve this we must add an artificial value to our enum. For this, we use PowerMock and Mockito. Consider the following enum:
public enum Day {
MONDAY, FRIDAY
}
Now, suppose an instance of Day
is evaluated in the following method using a switch
statement:
public void tellItLikeItIs(Day day) {
switch (day) {
case MONDAY:
System.out.println("Mondays are bad.");
break;
case FRIDAY:
System.out.println("Fridays are better.");
break;
default:
System.out.println("The other days are so-so.");
break;
}
}
In the current state of the Day
enum, all cases are covered and the default
statement is not executed. However we might want to ensure correct behaviour in the default
case using a unit test in case other days are added later.
We implement our testing strategy as follows:
@PrepareForTest(Day.class)
public class DayTest extends BaseTest {
@Mock
private Day additionalDay;
@Test
public void testTellItLikeItIsDefaultCase()
{
Day[] values = Day.values();
Day[] valuesAndAdditional = new Day[values.length + 1];
System.arraycopy(values, 0, valuesAndAdditional, 0, values.length);
// create additional, artificial Day
PowerMockito.mockStatic(Day.class);
Whitebox.setInternalState(additionalDay, "name", "ADDITIONAL_DAY");
Whitebox.setInternalState(additionalDay, "ordinal", values.length);
valuesAndAdditional[values.length] = additionalDay;
when(Day.values()).thenReturn(
valuesAndAdditional);
tellItLikeItIs(additionalDay);
// Tests for default case behaviour
// ...
}
Note that we need to annotate our Test with PrepareForTest
bound to our enum, as we perform a static mock on it later. For our mocked enum value, we set the name and ordinal attributes accordingly as these are evaluated in the switch statement. Finally, we overwrite the return value of the values
method of our enum to include the additional value.
Note that at this point in time there appears to be a bug in PowerMock which allows for correct mocking only when the enum-related method is executed first in the test class!
Ensuring that the method in question is executed first depends on your specific testing framework.