我有两个课程试图找出whenNew
的工作原理。
public class RockService {
public RockData serv() {
RockData rockData = new RockData();
rockData.setName("RockService");
rockData.setContent("content from rock service");
return rockData;
} }
和
public class RockData {
String name;
long id;
String content;
// get set method ignored
}
使用测试代码
@RunWith(PowerMockRunner.class)
@PrepareForTest(RockService.class)
public class MockNewInstanceCreation {
@Test
public void mockCreationTest() throws Exception {
RockData rockData = mock(RockData.class);
when(rockData.getName()).thenReturn("this is mock");
whenNew(RockData.class).withNoArguments().thenReturn(rockData);
RockService rockService = new RockService();
RockData servData = rockService.serv();
System.out.println(servData.getName());
System.out.println(servData.getContent());
}
}
所以在运行时,如果不是mock,输出(RockData's getName())
将是" RockService"。但是通过模拟,它返回"这是模拟"。该代码有效,但我仍然不知道Powermock / Mockito究竟是如何做到这一点的。
我调试了代码。困扰我的是在执行RockData rockData = new RockData();
之后,实际创建的内容正是由RockData rockData = mock(RockData.class);
创建的实例。这意味着new RockData()
根本不会创建新实例。它只返回了一个已创建的实例。在调试时,它跳转到MockGateway.newInstanceCall
。
那么Powermockito如何拦截新实例?
答案 0 :(得分:0)
PowerMockRunner使用特殊的类加载器运行测试 - org.powermock.core.classloader.MockClassLoader 。
不是加载真正的类,而是加载一个具有相同签名的新类。这意味着不会调用真正的构造函数。
因此new运算符返回的对象不是Mock。它是可以分配给真实类的不同类的实例,它返回模拟值。
请参阅以下代码:
public class RockService {
ClassLoader classLoader = this.getClass().getClassLoader();
System.out.println("Real construct");
//Different class loader
System.out.println(classLoader);
//The same class
System.out.println(this.getClass());
}
public RockData serv() {
RockData rockData = new RockData();
Class<? extends RockData> clazz = rockData.getClass();
//This is a different class
System.out.println("Mocked class: " + clazz.getCanonicalName());
//And different classloader
ClassLoader classLoader = clazz.getClassLoader();
System.out.println(classLoader);
//Mocked class instance could be assigned to real one
System.out.println(RockData.class.isAssignableFrom(clazz));
//it's instance of both RockData.class and mocked class
System.out.println(clazz.isInstance(rockData));
System.out.println(RockData.class.isInstance(rockData));
rockData.setName("RockService");
rockData.setContent("content from rock service");
return rockData;
}