Search code examples
javamockingmockitopowermockpowermockito

powermockito: How to mock abstract method in enum


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?


Solution

    1. Each constant in enum it's a static final nested class. So to mock it you have to pointe nested class in PrepareForTest.
    2. MyEnum.values() returns pre-initialised array, so it should be also mock in your case.
    3. Each Enum constant it is just public final static field.

    All together:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(
    value = MyEnum.class,
    fullyQualifiedNames = {
                              "com.stackoverflow.q45414070.MyEnum$1",
                              "com.stackoverflow.q45414070.MyEnum$2"
    })
    
    public class MyTestClass {
    
      @Test
      public void should_return_sum_of_stubs() throws Exception {
    
        final MyEnum one = mock(MyEnum.ONE.getClass());
        final MyEnum two = mock(MyEnum.TWO.getClass());
    
        mockStatic(MyEnum.class);
        when(MyEnum.values()).thenReturn(new MyEnum[]{one, two});
    
        when(one.myMethod()).thenReturn(10);
        when(two.myMethod()).thenReturn(20);
    
        assertThat(new Consumer().consumer())
            .isEqualTo(30);
      }
    
      @Test
      public void should_return_stubs() {
    
        final MyEnum one = mock(MyEnum.ONE.getClass());
    
        when(one.myMethod()).thenReturn(10);
    
        Whitebox.setInternalState(MyEnum.class, "ONE", one);
    
        assertThat(MyEnum.ONE.myMethod()).isEqualTo(10);
      }
    
    }
    

    Full example