zoukankan      html  css  js  c++  java
  • cglib与mock,自研mockito

    逻辑:

    natvie test无法搞定db,也不能在unittest环节搞定——引出mockito

    mockito无法处理injectmock 非public方法的when、verify——引出simple mockito(实际上mockto可以处理protected inner function,只要handler和handlertest在同一个package下

    小结论:

    1 被mock的对象不用when,什么都不做,有返回的会默认构造一个,我们沿用

    2 mockito的when、verify参数根据equals方法match,我们沿用

    public class MyApplication {
    //    @Override
    //    public boolean equals(Object obj) {
    //        return true;
    //    }
    }
    

      

    3 unittest为每个@Test建立一个实例,因此MethodInteceptor如下考虑多线程

    abstract public class AbstractSimpleMockProxyFactory implements MethodInterceptor {
    
        /**
         * cglib enhance object -> origin object map
         * 因为2个test会并发跑,多线程读写此static对象,需要concurrent
         */
        public static Map<Object, AbstractSimpleMockProxyFactory> map = new ConcurrentHashMap<>();
    
        // origin object
        protected Object target;
    
        /**
         * 同一个mock or injectmock对象只有一条线程操作,因为每个Test方法都创建一个test实例
         * 尽管会并发跑2个test,但读写的是不同的 mocker or inject mocker.counter/whenReturn
         * 不需要concurrent
         */
        protected Map<FunctionMatcher, RetCount> counter = new HashMap<>();
        protected Map<FunctionMatcher, Object> whenReturn = new HashMap<>();
    

      

    4 proxy object->MethodIntecept反向映射

    被代理的对象不改写的方法hashcode和equels同样被拦截 java 的三种代理模式 (二)——子函数切面,两种方式:

    1)使用System.idendifyHashcode + classname构建key

    getClass不在cliib默认拦截范畴内

    注意前者极端情况下会冲突 hashcode & System.identityHashCode

    2)继续使用proxy object作为hashmap key,但在cglib intecept中放行hashcode equals至基类(除非用户when return了)

           /**
             * 对于@Mock对象,建立cglib enhance object -> origin object map映射时需要
             */
            if(method.getName().equals("hashcode") || method.getName().equals("equals"))
                return proxy.invokeSuper(obj, args);
    
            /**
             * 对于@Mock对象其它没有whenReturn,也不是hashcode和equals的隐藏未覆盖方法不做处理
             * 如clone、finalize、toString
             * getClass、notify、notifyAll、wait本不在其列
             */
         //   Object returnValue = proxy.invokeSuper(obj, args);
    
            Class cRet = method.getReturnType();
    

      

    对于@Mock对象,总是为其代理

    对于@InjectMock对象,有@Spy时代理,无时使用Test里原始对象

    10 原理

    test对象t中,存在@InjectMock,类型A的对象a=new A,依赖C1类型对象b1、C2类型对象b2(ioc或new),t中存在@Mock的C1类型对象d1=null、C2类型对象d2=null,则——

    1) mockito模式

    调用Mockito.initMocks

    Mockito为a生成代理da,为d1、d2生成代理pd1、pd2,遍历A的成员,如果类型匹配,则将pd1、pd2赋予,此处da.b1=pd1、da.b2=pd2

    2)hybrid模式

    调用Mockito.initMocks

    Mockito为a生成代理da,为d1、d2生成代理pd1、pd2,遍历A的成员,如果类型匹配,则将pd1、pd2赋予,此处da.b1=pd1、da.b2=pd2

    调用SimpleMock.injectHybrid

    为a生成代理sa,遍历A的成员,sa.b1=da.b1、sa.b2=da.b2

    3)SimpleMock模式

    调用SimpleMock.inject

    为a生成代理sa,为d1、d2生成代理sd1、sd2,遍历A的成员,如果类型匹配,则将sd1、sd2赋予,此处sa.b1=sd1、sa.b2=sd2

    不足:

    matcher无法从精到粗的匹配,同一个@Test方法不允许对同一个对象,同一种类型(verify or when)同时做any() 和精确值

    对@Mock对象的返回为基本类型的方法,无法创建默认对象;对Integer方法 newInstance不能调用有参数构造函数

    2021.2.14 补充mock基类protected方法

    其它:

    mockito能不能直接 mock @Spy对象 的protected,同包就可以,故使用mockito时,遵循 handler-handlerTest全限定性名相同的规范

    但对于非同包的基类protected方法,mockito没有办法,我的SimpleMock由于api而可以

    mockito的api设计的太友好了,以至于也有这样的缺点

  • 相关阅读:
    简单RPC框架-业务线程池
    简单RPC框架-基于Consul的服务注册与发现
    简易RPC框架-学习使用
    统一配置中心2
    dubbo+zipkin调用链监控
    Spring Cache扩展:注解失效时间+主动刷新缓存
    转:深入理解Java G1垃圾收集器
    dubbo源码分析(一)
    理解WEB API网关
    理解zookeeper选举机制
  • 原文地址:https://www.cnblogs.com/silyvin/p/13756988.html
Copyright © 2011-2022 走看看