每个 @InjectMocks 调用都没有考虑 PowerMock 静态方法模拟
PowerMock static method mocking isn't taken into account for each @InjectMocks invocation
我想编写一些使用 JUnit 4.12、Mockito 1.9.5 和 PowerMock 1.6.1 的单元测试。
class 有一些字段用@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();
}
}
如前所述,第一个测试通过并且 StaticClass.staticMethod() 被 PowerMock 预期的模拟。
第二个测试没有通过,当对值调用 someOtherMethod 时,它在行中抛出 NullPointerException(因为 value = null,因为 StaticClass.staticMethod 不再被 PowerMock 模拟)。
如 (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;
}
首选方法是使用 SomeOtherClass
、
的构造函数提供 attribute
,但是因为您似乎使用了空构造函数
您将不得不从外部设置值。
如果 attribute
实例不可访问,您可能被迫使用反射。
更简洁的方法是重构您 SomeOtherClass
的构造函数,使其不在内部使用静态方法。而是将 SomeConcreteClass
作为参数传递给构造函数是可行的方法。
有些人甚至说你不应该在构造函数中包含任何逻辑。
我想编写一些使用 JUnit 4.12、Mockito 1.9.5 和 PowerMock 1.6.1 的单元测试。 class 有一些字段用@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();
}
}
如前所述,第一个测试通过并且 StaticClass.staticMethod() 被 PowerMock 预期的模拟。 第二个测试没有通过,当对值调用 someOtherMethod 时,它在行中抛出 NullPointerException(因为 value = null,因为 StaticClass.staticMethod 不再被 PowerMock 模拟)。
如 (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;
}
首选方法是使用 SomeOtherClass
、
的构造函数提供 attribute
,但是因为您似乎使用了空构造函数
您将不得不从外部设置值。
如果 attribute
实例不可访问,您可能被迫使用反射。
更简洁的方法是重构您 SomeOtherClass
的构造函数,使其不在内部使用静态方法。而是将 SomeConcreteClass
作为参数传递给构造函数是可行的方法。
有些人甚至说你不应该在构造函数中包含任何逻辑。