4
votes

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).

1
Did you try using @Before instead of @BeforeClass?second
Using @Before doesn't help me at all because InjectMocks is invoked before each test run and Before method is called afterwards. But the constructor of the object I need has the static method calls that should have been mocked.Andrei Roșu-Cojocaru
On another note: You're using the when expression on a non mocked object attribute2 (your class under test). This is bound to fail. You might have made a typo and wanted to use attribute1 instead?second
Indeed, the when usage is a bad example, it is not as such in the real code. I just put it there to demonstrate I really need the attribute2 instance to be injected with some mocks.Andrei Roșu-Cojocaru

1 Answers

2
votes

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.