Andrei Roșu-Cojocaru
Andrei Roșu-Cojocaru

Reputation: 509

PowerMock static method mocking isn't taken into account for each @InjectMocks invocation

I want to write some unit tests, that use JUnit 4.12, Mockito 1.9.5 and PowerMock 1.6.1. The class has some fields annotated with @Mock, as well as some fields annotated with @InjectMocks. The attribute that is annotated with @InjectMocks reaches at some point a parent constructor which contains some static method invokation, that should be mocked with PowerMock. The problem is the first test works seamlessly, while the second test does not seem to mock the static methods at all.

@RunWith(PowerMockRunner.class)
@PrepareForTest({ StaticClass.class })
public class TestClass {
  @Mock
  private SomeClass attribute1;
  @InjectMocks
  private SomeOtherClass attribute2;

  @BeforeClass
  public static void setUp() {
    PowerMockito.mockStatic(StaticClass.class);

 when(StaticClass.staticMethod(any(), any()).thenReturn(new SomeConcreteClass());
  }

  @Test
  public void test1() {
    assertEquals(attribute2.method1(), value1);
  }

  @Test
  public void test2() {
    assertEquals(attribute2.method2(), value2);
  }
}

public class SomeOtherClass {
  private SomeClass attribute;
  public SomeOtherClass() {
    SomeConcreteClass value = StaticClass.staticMethod(argument1, argument2);
    value.someOtherMethod();
  }
}

As mentioned before, the first test passes and the StaticClass.staticMethod() is mocked as expected by PowerMock. The second test does not pass and it throws a NullPointerException at line when someOtherMethod is called on value (because value = null, as the StaticClass.staticMethod was not mocked anymore by PowerMock).

Upvotes: 4

Views: 1969

Answers (1)

second
second

Reputation: 4259

As explained in (Mocking behaviour resets after each test with PowerMock) Powermock resets the mocks before each test.

For some reason it works the first time - there exists an unresolved bug report for that issue (https://github.com/powermock/powermock/issues/398).


Its arguably bad design, but a way to do what you want is the following:
Instead of relying on the annotation set up the mocks manually.

private SomeClass attribute;
private SomeOtherClass testClass;

@Before
public void setUp() {
    PowerMockito.mockStatic(StaticClass.class);
    Mockito.when(StaticClass.staticMethod(anyString())).thenReturn(new SomeConcreteClass());

    attribute = Mockito.mock(SomeClass.class);      
    testClass = new SomeOtherClass();

    // assign mock manually
    testClass.attribute = attribute;
}

The prefered way would be to supply the attribute using the constructor of SomeOtherClass,
however since you seem to use a empty constructor you will have to set the value from the outside.
If the attribute instance is not accessible you might be forced to use reflections.


The cleaner way would be to refactor the constructor of you SomeOtherClass to not use a static method inside. Instead passing SomeConcreteClass as a parameter to the constructor is the way to go.

Some people even say you should not have any logic inside of a constructor.

Upvotes: 2

Related Questions