Consider the following (simplified) enumeration:
MyEnum {
ONE public int myMethod() {
// Some complex stuff
return 1;
},
TWO public int myMethod() {
// Some complex stuff
return 2;
};
public abstract int myMethod();
}
This is used in a function like:
void consumer() {
for (MyEnum n : MyEnum.values()) {
n.myMethod();
}
}
I'd now like to write a unit test for consumer
that mocks out the calls to myMethod() in each of the enumeration instances. I've tried the following:
@RunWith(PowerMockRunner.class)
@PrepareForTest(MyEnum.class)
public class MyTestClass {
@Test
public void test() throws Exception {
mockStatic(MyEnum.class);
when(MyEnum.ONE.myMethod()).thenReturn(10);
when(MyEnum.TWO.myMethod()).thenReturn(20);
// Now call consumer()
}
But the real implementations of ONE.myMethod()
and TWO.myMethod()
are being called.
What have I done wrong?
MyEnum.values()
returns pre-initialised array, so it should be also mock in your case.public final static
field.All together:
Full example
That is the crux with using enums for more than "compile time constants" - enum classes are final by default (you can't extend MyEnum). So dealing with them within unit test can be hard.
@PrepareForTest means that PowerMock will generate byte code for the annotated class. But you can't have it both ways: either the class is generated (then it doesn't contain ONE, TWO, ...) or it is "real" - and then you can't override behavior.
So your options are:
values()
to return a list of mocked enum class objects ( see here for the first part )myMethod()
and have your enum implement that. And then you don't usevalues()
directly - instead you introduce some kind of factory that simply returns aList<TheNewInterface>
- and then the factory can return a list of mocked objects for your unit test.I strongly recommend option 2 - as that will also improve the quality of your code base (by cutting the tight coupling to the enum class and its constants that your code currently deals with).
From what I know about PowerMock, your test should work as is. Maybe you could open an issue in the PowerMock github project?
Anyway, here is a self-contained test that does work, but using another library, JMockit:
As you can see, the test is quite short and simple. However, I would recommend to not mock an enum unless you have a clear need to do so. Don't mock it just because it can be done.