我想编写一些单元测试,使用JUnit 4.12,Mockito 1.9.5和PowerMock 1.6.1。 该类有一些用@Mock注释的字段,以及一些用@InjectMocks注释的字段。 用@InjectMocks注释的属性在某个时候到达父构造函数,该父构造函数包含一些静态方法调用,应该使用PowerMock对其进行模拟。 问题在于第一个测试可以无缝运行,而第二个测试似乎根本没有模拟静态方法。
@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();
}
}
如前所述,第一个测试通过,并且PowerMock按预期模拟了StaticClass.staticMethod()。 在值上调用someOtherMethod时,第二项测试未通过,并且在行上引发NullPointerException(因为value = null,因为PowerMock不再模拟StaticClass.staticMethod)。
答案 0 :(得分:1)
如(Mocking behaviour resets after each test with PowerMock中所述,Powermock会在每次测试之前重置模拟。
由于某种原因,它第一次起作用-存在
该问题的未解决错误报告(https://github.com/powermock/powermock/issues/398)。
它可以说是糟糕的设计,但是可以按照以下方法做:
不必依赖注释,而是手动设置模拟。
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;
}
首选方式是使用attribute
的构造函数提供SomeOtherClass
,
但是,由于您似乎使用了空的构造函数
您将必须从外部设置该值。
如果无法访问attribute
实例,则可能被迫使用反射。
更简洁的方法是重构您的SomeOtherClass
的构造函数,使其内部不使用静态方法。替代方法是将SomeConcreteClass
作为参数传递给构造函数。
甚至有人说您不应在构造函数内部包含任何逻辑。