美文网首页
JMockit/Mockito/PowerMockit/Robo

JMockit/Mockito/PowerMockit/Robo

作者: 普通的程序员 | 来源:发表于2020-08-31 17:15 被阅读0次

    目录

    • 概念学习
    • 代理模式
    • mockito原理
    • PowerMockito原理
    • Robolectric 原理
    • JMockit原理
    • 多说几句

    概念学习

    要学习几个框架的原理,首先必须了解以下几个概念
    代理模式
    静态代理
    动态代理
    CGLIB
    ASM
    ByteBuddy

    代理模式/静态代理/动态代理

    代理模式就不多说了
    https://www.runoob.com/design-pattern/proxy-pattern.html

    这里讲的静态代理,就是代理模式的最基本的一种实现方式,
    在开发者编程的时候定义好接口interface,也写好 该接口的实现类proxy class(代理类),
    这种就是叫静态代理。

    动态代理的意思就是,这个interface已经定义好了,但是实现类,是在运行时,通过某种方式在内存里创建的。
    通过java提供的
    Proxy类,InvocationHandler接口等api完成动态生成。
    底层实现是,通过指定的classLoader,利用反射,完成代理类proxy class的生成,具体怎么生成的可自行跟踪

    关键代码
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
    return defineClass0(loader, proxyName,
                        proxyClassFile, 0, proxyClassFile.length);
    

    参考链接
    https://blog.csdn.net/riemann_/article/details/86777505

    JDK动态代理之实现与原理

    CGLIB/ASM

    其实cglib跟以上的静态动态代理不同,cglib是一个库,后者是一个理念(具体实现是反射创建类),同理ASM也只是一个库,这里能放在一起比较,只是单纯从代理的角度去做比较。

    cglib提供Enhance等api,将真实对象类的class文件加载进来,通过ASM修改字节码生成其子类,覆盖父类相应的方法(真正在修改字节码的是ASM库)

    CGLIB和Java动态代理的区别

    • Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承),CGLIB则可以要求实现类不用实现任何接口。CGLIB动态生成的代理类会继承我们的业务类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等)

    • Java动态代理使用Java原生的反射API进行操作,在生成类上比较高效;CGLIB使用ASM框架直接对字节码进行操作,在类的执行过程中比较高效

    可以参考
    https://zhuanlan.zhihu.com/p/35144462
    看下cglib生成一个代理类的过程

    参考链接
    CGLIB动态代理实现与原理

    Android ASM框架详解

    mockito原理

    一句话『java动态代理+byteBuddy生成字节码』

    mock对象的创建主要是为了创建一个mock对象的代理类,使得代理类代理mock对象的所有方法(从源码设计中包含了私有方法,但是受私有方法封装性原因,该私有方法无法进行mock).

    mock实例方法的场景利用了Java运行时多态的原理,通过重写父类的方法来修改某个方法的行为。具体细节:
    mockito首先接受一个指定的class类型,采用java的动态代理逻辑,使用了ByteBuddy框架来生成该class类型的代理实例。(ByteBuddy这个框架,它并不需要编译器的帮助,而是直接生成class,然后使用ClassLoader来进行加载)

    代理对象继承了被mock类,为了对每个方法做拦截,通过byte buddy设置拦截器 MockMethodInterceptor。MockMethodInterceptor的主要作用是将mock对象的拦截方法执行交给了MockHandler来处理。

    具体代码跟踪
    https://albenw.github.io/posts/9758301d/

    后续的关键点就在这个ByteBuddy工具怎么生成动态类对象了。

    PowerMockito原理

    动态代理+ javassist修改字节码+ objenesis绕过构造方法来实例化对象

    PowerMockito比Mockito强大的地方在

    • 当某个测试方法被注解@PrepareForTest标注以后,在运行测试用例时,会创建一个新的org.powermock.core.classloader.MockClassLoader实例,然后加载该测试用例使用到的类(系统类除外)。
    • PowerMock会根据你的mock要求,去修改写在注解@PrepareForTest里的class文件(当前测试类会自动加入注解中),以满足特殊的mock需求。例如:去除final方法的final标识,在静态方法的最前面加入自己的虚拟实现等。
    • 如果需要mock的是系统类的final方法和静态方法,PowerMock不会直接修改系统类的class文件,而是修改调用系统类的class文件,以满足mock需求。

    参考链接
    https://www.cnblogs.com/zjdxr-up/p/11571207.html

    Robolectric 原理

    ASM 修改字节码 + classLoader替换
    https://www.jianshu.com/p/0848a47d37ab

    JMockit原理

    先使用asm修改原有class的字节码, 再利用jdk的instrument机制替换现有class的内容(使用的工具是agent)
    从而达到mock的目的。

    整个mock过程看
    参考链接
    https://zhuanlan.zhihu.com/p/106882864

    对比

    一个十年前的提问
    https://stackoverflow.com/questions/4105592/comparison-between-mockito-vs-jmockit-why-is-mockito-voted-better-than-jmockit

    版本都与现在不一样了。
    按高票的意思是,JMockit更加灵活。

    相关文章

      网友评论

          本文标题:JMockit/Mockito/PowerMockit/Robo

          本文链接:https://www.haomeiwen.com/subject/exxpsktx.html