Reputation: 509
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
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