Mock,PowerMock的底层原理是怎样的?原理详解

KLQ 2020-06-29 14:16:41 java常见问答 5004

对于PowerMock的底层原理你了解多少呢?很多人表示,对这个原理不大清楚,那么下面就一起通过以下的文章内容来进行一下了解吧。

首先的话我们要来看一看PowerMock的依赖,PowerMock有着两个非常重要的依赖,一个是javassist,另外一个就是objenesis,下面分别来简单的对这两者进行一下介绍。

1、javassist

javassist是一个修改java字节码的工具包;

2、objenesis

objenesis是一个绕过构造方法来实例化一个对象的工具包;

PowerMock的本质是通过修改字节码来实现对静态和final等方法的mock的。

@RunWith(PowerMockRunner.class)
public class TestClassUnderTest
{
    @Test
    public void testCallArgumentInstance()
    {
        showClassLoader("testCallArgumentInstance");
        File file = PowerMockito.mock(File.class);
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.when(file.exists())
            .thenReturn(true);
        Assert.assertTrue(underTest.callArgumentInstance(file));
    }
    @Test
    @PrepareForTest(ClassUnderTest.class)
    public void testCallInternalInstance() throws Exception
    {
        showClassLoader("testCallInternalInstance");
        File file = PowerMockito.mock(File.class);
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.whenNew(File.class)
            .withArguments("bbb")
            .thenReturn(file);
        PowerMockito.when(file.exists())
            .thenReturn(true);
        Assert.assertTrue(underTest.callInternalInstance("bbb"));
    }
    @Test
    @PrepareForTest(ClassDependency.class)
    public void testCallFinalMethod()
    {
        showClassLoader("testCallFinalMethod");
        ClassDependency depencency = PowerMockito.mock(ClassDependency.class);
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.when(depencency.isAlive())
            .thenReturn(true);
        Assert.assertTrue(underTest.callFinalMethod(depencency));
    }
    private void showClassLoader(String methodName)
    {
        System.out.println("==============" + methodName + "===============");
        System.out.println("TestClassUnderTest: " + TestClassUnderTest.class.getClassLoader());
        System.out.println("ClassUnderTest: " + ClassUnderTest.class.getClassLoader());
        System.out.println("ClassDependency: " + ClassDependency.class.getClassLoader());
    }
}

下面来介绍一下PowerMock实现原理。

其实PowerMock的实现原理还是比较简单的。

在某一个测试方法被注解@PrepareForTest标注之后,在运行测试用例的时候,会创建一个新的org.powermock.core.classloader.MockClassLoader实例,之后,加载这个测试用例使用到的类,注意这里的话,系统类要除外。

PowerMock会依据你的mock要求,对在注解@PrepareForTest里的class文件进行修改(测试类会自己主动的加入注解当中),以此来满足特殊的mock需求。

例:

去除final方法的final标识,在静态方法的最前面加入自己的虚拟实现等等。

假如,需要mock的是系统类的final方法和静态方法,PowerMock不会说直接修改系统类的class文件,而是去修改调用系统类的class文件,以此来满足mock需求。

也许在没有看到PowerMock的源码之前,很多人都会有这样的问题,PowerMock是如何mock系统类的final方法和静态方法的呢?难不成它还真的是能修改了系统类的类文件,因为系统的类文件是被Boostarp ClassLoader加载的,应用程序不能够去修改它,所以就非常的好奇了,但是看了PowerMock的源码之后就发现,原来PowerMock其实并没有去修改系统类,它只是修改了调用系统类的地方,这样的话就十分的明朗了。

以上就是对PowerMock原理的一个简单小总结了,你都了解了吗?你还想了解更多和PowerMock相关的常见问题吗?请继续通过奇Q工具网来进行了解吧。

推荐阅读:

java字节码对象,获取字节码的三种方式是什么?

字节码文件的扩展名都有哪些?java字节码文件扩展名是什么?

java blockingqueue原理是什么?原理详解