PowerMockito如何拦截新实例



我有两个类来弄清楚 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());
    }
}

因此,在运行时,如果不是模拟,则输出(RockData's getName())将是"摇滚服务"。但是有了模拟,它返回"这是模拟"。该代码有效,但我仍然不知道PowerMock/Mockito是如何做到这一点的。

我调试了代码。在执行RockData rockData = new RockData();之后,我感到困惑的是,实际创建的完全是RockData rockData = mock(RockData.class);创建的实例。这意味着new RockData()根本不会创建新实例。它刚刚返回了已经创建的实例。在调试时,它跳到MockGateway.newInstanceCall

那么PowerMockito如何拦截新实例?

powermockrunner使用特殊类加载程序 - org.powermock.core.classloader.mockclassloader 进行测试。

而不是加载真实类,而是加载具有相同签名的新类别。这意味着不会调用真正的构造函数。

因此,新操作员返回的对象不是模拟。它是可以分配给真实类别的不同类的实例,并返回模拟的值。

请参阅下面的代码:

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;
} 

相关内容

  • 没有找到相关文章

最新更新