Unit testing 更换PowerMock';s@PrepareForest是否以编程方式进行?
我在junit测试中使用PowerMock模拟静态方法,通常如下所示:Unit testing 更换PowerMock';s@PrepareForest是否以编程方式进行?,unit-testing,junit,powermock,Unit Testing,Junit,Powermock,我在junit测试中使用PowerMock模拟静态方法,通常如下所示: @RunWith(PowerMockRunner.class) @PrepareForTest({Foo.class,Bar.class}) 公共类单元测试{ @以前 公共测试(){ setUpFoo(); 设置栏(); } 私有void setUpFoo(){ mockStatic(Foo.class); when(Foo.someStaticMethod())。然后返回(1); } 专用void setUpBar(){
@RunWith(PowerMockRunner.class)
@PrepareForTest({Foo.class,Bar.class})
公共类单元测试{
@以前
公共测试(){
setUpFoo();
设置栏();
}
私有void setUpFoo(){
mockStatic(Foo.class);
when(Foo.someStaticMethod())。然后返回(1);
}
专用void setUpBar(){
mockStatic(Bar.class);
when(Bar.someStaticMethod())。然后返回(2);
}
@试验
public void someTestCase(){
...
}
}
这很好,但我发现指定@PrepareForTest
注释会妨碍我使测试API变得灵活
我想做的事情如下:
公共类MockLibraryOne{
公共静态无效设置LibraryOne(){
setUpFoo();
设置栏();
}
私有静态void setUpFoo(){
mockStatic(Foo.class);
when(Foo.someStaticMethod())。然后返回(1);
}
私有静态void setUpBar(){
mockStatic(Bar.class);
when(Bar.someStaticMethod())。然后返回(2);
}
}
@RunWith(PowerMockRunner.class)
公共类单元测试{
@以前
公共测试(){
MockLibraryOne.setUpLibraryOne();
}
@试验
public void someTestCase(){
...
}
}
这里,我的单元测试依赖于LibraryOne
,但它不知道LibraryOne
依赖哪些类,因此它不知道要添加到@PrepareForTest
注释中的类
我可以制作SomeUnitTest
扩展MockLibraryOne
,并将@PrepareForTest
注释添加到MockLibraryOne
类中,但在其他单元测试中,我的依赖性不仅仅是MockLibraryOne
,因此继承不是一个通用的解决方案
是否有某种方法可以通过编程来准备一个类,以便在PowerMock下进行测试,而不是使用@PrepareForTest
注释?例如,如下所示:
公共类MockLibraryOne{
公共静态无效设置LibraryOne(){
setUpFoo();
设置栏();
}
私有静态void setUpFoo(){
准备考试(食品类);
mockStatic(Foo.class);
when(Foo.someStaticMethod())。然后返回(1);
}
私有静态void setUpBar(){
准备测试(酒吧级别);
mockStatic(Bar.class);
when(Bar.someStaticMethod())。然后返回(2);
}
}
如果PowerMockRunner
对@PrepareForTest
注释的处理有点不同,我想这会很好:对于每个指定的类,它不仅应该将该类(及其层次结构)添加到类列表中以准备模拟,然后检查该类,看看它是否也有@PrepareForTest
注释:
@RunWith(PowerMockRunner.class)
@PrepareForTest({MockLibraryOne.class})
公共类单元测试{
...
}
@PrepareForTest({Foo.class,Bar.class})
公共类MockLibraryOne{
...
}
}
因此在这里,SomeUnitTest
上的@PrepareForTest
注释将找到MockLibraryOne
,那里的@PrepareForTest
注释也将拖入Foo.class
和Bar.class
因此,也许编写我自己的测试运行程序来替换PowerMockRunner
可能是一个解决方案
或者有一个更简单的解决方案,例如使用PowerMockAgent
类
编辑:模拟策略可能是一种解决方案:
编辑:Mock策略与
PowerMockRunner
配合使用,但与PowerMockRule
配合使用(似乎)不起作用(由于类加载器问题,我有时需要这样做)。也许您正在寻找一个?为什么要模拟静态方法?为什么不将这些静态方法封装在一个可以用mockito模拟的类中呢
class FooWraper {
void someMethod() {
Foo.someStaticMethod()
}
}
然后,您可以创建一个Foowrapper的模拟。根本不需要使用Powermock…您能帮忙吗(摘自文档)
您还可以使用通配符准备整个测试包:
@PrepareForTest(fullyQualifiedNames=“com.mypackage.*”)
因此,您可以将整个库添加到您的prepare…您试图实现的目标将不起作用 问题是powermock必须重写客户机类的代码以拦截静态调用,而在类加载后它不能这样做。因此,它只能在加载类之前为测试准备类 假设您想在下面的简单类中模拟
System.currentTimeMillis
调用
class SystemClock {
public long getTime() {
return System.currentTimeMillis();
}
}
Powermock不会更改java.lang.System.currentTimeMillis的代码,因为它不能更改。相反,它会更改SystemClock
的字节码,以便不再调用System.currentTimeMillis
。相反,它调用属于powermock的其他对象
这就是powermock get完全控制返回值的方式,并允许您编写如下测试:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ SystemClock.class })
public class PowerMockitoTest {
@Test
public void systemTimeMillis() {
SystemClock systemClock = new SystemClock();
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.currentTimeMillis()).thenReturn(12345L);
long time = systemClock.getTime();
assertEquals(12345L, time);
}
}
您可以看到powermock已经在调试器的stacktrace中重写了客户机类。在SystemClock.getTime
上设置断点,然后进入调用的方法
如您所见,SystemClock
调用MockGateway
如果查看MockGateway
调用堆栈上的变量,可以看到原始System.currentTimeMillis
方法是如何处理的
谢谢您的回复。我调查了
MockPolicy
,但如上所述,它只适用于PowerMockRunner
,而不适用于PowerMockRule
。由于类加载器问题,我需要使用PowerMockRule
,而MockPolicy
初始值设定项仅适用于PowerMockRunner
提供的MockClassLoader
。我面临同样的问题。你找到解决办法了吗?找到了吗