powermock源码浅析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a040600145/article/details/54587920

一.基本构成

.初始化过程

 通过初始化MockClassLoader并通过该ClassLoader加载配置的@PrepareForTest类,通过javassit修改对应类的字节码,在方法调前加上类似的 Object localObject = MockGateway.methodCall(this, "testFinal", new Object[0], Desc.getParams("()"), ""); if (localObject != MockGateway.PROCEED) return,以满足特殊的mock需求。

Abstractmainmocktransformer.modifymethod代码
  1. private void modifyMethod(CtMethod method, CtClass returnTypeAsCtClass,  
  2.                               String returnTypeAsString) throws CannotCompileException {  
  3.         final String returnValue = getCorrectReturnValueType(returnTypeAsCtClass);  
  4.   
  5.         String classOrInstance = classOrInstance(method);  
  6.   
  7.         String code = "Object value = "  
  8.                               + MockGateway.class.getName()  
  9.                               + ".methodCall("  
  10.                                 + classOrInstance + ", \""  
  11.                                 + method.getName()  
  12.                                 + "\", $args, $sig, \""  
  13.                                 + returnTypeAsString  
  14.                               + "\");"  
  15.                               + "if (value != " + MockGateway.class.getName() + ".PROCEED) " + "return "  
  16.                               + returnValue + "; ";  
  17.   
  18.         method.insertBefore("{ " + code + "}");  
  19.     }  

    线程堆栈信息如下:

三.mock过程

     PowerMockito的spy和mock方法最后都是调用的DefaultMockCreator.mock

Defaultmockcreator.createmock代码
  1. @Override  
  2.    public <T> T createMock(Class<T> type, boolean isStatic, boolean isSpy, Object delegator,  
  3.                            MockSettings mockSettings, Method... methods) {  
  4.        if (type == null) {  
  5.            throw new IllegalArgumentException("The class to mock cannot be null");  
  6.        }  
  7.   
  8.        validateType(type, isStatic, isSpy);  
  9.   
  10.        final String mockName = toInstanceName(type, mockSettings);  
  11.   
  12.        MockRepository.addAfterMethodRunner(new MockitoStateCleanerRunnable());  
  13.   
  14.        final Class<T> typeToMock;  
  15.        if (isFinalJavaSystemClass(type)) {  
  16.            typeToMock = (Class<T>) new ClassReplicaCreator().createClassReplica(type);  
  17.        } else {  
  18.            typeToMock = type;  
  19.        }  
  20.   
  21.        final MockData<T> mockData = createMethodInvocationControl(mockName, typeToMock, methods, isSpy, delegator,  
  22.                mockSettings);  
  23.   
  24.        T mock = mockData.getMock();  
  25.        if (isFinalJavaSystemClass(type) && !isStatic) {  
  26.            mock = Whitebox.newInstance(type);  
  27.            DefaultFieldValueGenerator.fillWithDefaultValues(mock);  
  28.        }  
  29.   
  30.        if (isStatic) {  
  31.            MockRepository.putStaticMethodInvocationControl(type, mockData.getMethodInvocationControl());  
  32.        } else {  
  33.            MockRepository.putInstanceMethodInvocationControl(mock, mockData.getMethodInvocationControl());  
  34.        }  
  35.   
  36.        if (isSpy) {  
  37.            new LenientCopyTool().copyToMock(delegator, mock);  
  38.        }  
  39.   
  40.        return mock;  
  41.    } 
Defaultmockcreator.createmethodinvocationcontrol代码
  1. private <T> MockData<T> createMethodInvocationControl(final String mockName, Class<T> type,  
  2.                                                          Method[] methods, boolean isSpy, Object delegator, MockSettings mockSettings) {  
  3.        final MockSettingsImpl settings;  
  4.        if (mockSettings == null) {  
  5.            // We change the context classloader to the current CL in order for the Mockito  
  6.            // framework to load it's plugins (such as MockMaker) correctly.  
  7.            final ClassLoader originalCL = Thread.currentThread().getContextClassLoader();  
  8.            Thread.currentThread().setContextClassLoader(DefaultMockCreator.class.getClassLoader());  
  9.            try {  
  10.                settings = (MockSettingsImpl) Mockito.withSettings();  
  11.            } finally {  
  12.                Thread.currentThread().setContextClassLoader(originalCL);  
  13.            }  
  14.        } else {  
  15.            settings = (MockSettingsImpl) mockSettings;  
  16.        }  
  17.   
  18.        if (isSpy) {  
  19.            settings.defaultAnswer(Mockito.CALLS_REAL_METHODS);  
  20.        }  
  21.   
  22.        settings.setMockName(new MockNameImpl(mockName));  
  23.        settings.setTypeToMock(type);  
  24.   
  25.        InternalMockHandler mockHandler = new MockHandlerFactory().create(settings);  
  26.        MethodInterceptorFilter filter = new PowerMockMethodInterceptorFilter(mockHandler, settings);  
  27.        final T mock = new ClassImposterizer(new InstantiatorProvider().getInstantiator(settings)).imposterise(filter, type);  
  28.        ClassLoader classLoader = mock.getClass().getClassLoader();  
  29.        if (classLoader instanceof MockClassLoader) {  
  30.            MockClassLoader mcl = (MockClassLoader) classLoader;  
  31.            mcl.cache(mock.getClass());  
  32.        }  
  33.        final MockitoMethodInvocationControl invocationControl = new MockitoMethodInvocationControl(  
  34.                filter,  
  35.                isSpy && delegator == null ? new Object() : delegator,  
  36.                mock,  
  37.                methods);  
  38.   
  39.        return new MockData<T>(invocationControl, mock);  
  40.    } 
Classimposterizer.imposterise代码
  1. public <T> T imposterise(final MethodInterceptor interceptor, Class<T> mockedType, Class<?>... ancillaryTypes) {  
  2.         Class<Factory> proxyClass = null;  
  3.         Object proxyInstance = null;  
  4.         try {  
  5.             setConstructorsAccessible(mockedType, true);  
  6.             proxyClass = createProxyClass(mockedType, ancillaryTypes);  
  7.             proxyInstance = createProxy(proxyClass, interceptor);  
  8.             return mockedType.cast(proxyInstance);  
  9.         } catch (ClassCastException cce) {  
  10.             throw new MockitoException(join(  
  11.                 "ClassCastException occurred while creating the mockito proxy :",  
  12.                 "  class to mock : " + describeClass(mockedType),  
  13.                 "  created class : " + describeClass(proxyClass),  
  14.                 "  proxy instance class : " + describeClass(proxyInstance),  
  15.                 "  instance creation by : " + instantiator.getClass().getSimpleName(),  
  16.                 "",  
  17.                 "You might experience classloading issues, disabling the Objenesis cache *might* help (see MockitoConfiguration)"  
  18.             ), cce);  
  19.         } finally {  
  20.             setConstructorsAccessible(mockedType, false);  
  21.         }  
  22.     } 

四.mock类非final和static方法的调用

  线程堆栈信息如下:

五.mock类的final方法调用

   线程堆栈信息如下:

当spy时MockSettingsImpl.defaultAnswer为CallsRealMethods,其方法调用时MockedRealMethod会先调用notMockNextCallIfRequired新增MockGateway.DONT_MOCK_NEXT_CALL为true的AdditionalState,使其MockGateway.methodCall返回MockGateway.PROCEED从而调用原方法。

Mockedrealmethod.invoke代码
  1. public Object invoke(Object target, Object[] arguments) throws Throwable {  
  2.            /*  
  3.                 * Instruct the MockGateway to don't intercept the next call.  
  4.                 * The reason is that when Mockito is spying on objects it  
  5.                 * should call the "real method" (which is proxied by Mockito  
  6.                 * anyways) so that we don't end up in here one more time which  
  7.                 * causes infinite recursion. This should not be done if the  
  8.                 * interceptionObject is a final system class because these are  
  9.                 * never caught by the Mockito proxy.  
  10.                 */  
  11.            notMockNextCallIfRequired();  
  12.            try {  
  13.                return method.invoke(target, arguments);  
  14.            } catch (InvocationTargetException e) {  
  15.                SafeExceptionRethrower.safeRethrow(e.getCause());  
  16.            }  
  17.            return null;  
  18.        } 
Mockedrealmethod.notmocknextcallifrequired代码
  1. private void notMockNextCallIfRequired() {  
  2.             final Class<?> type = Whitebox.getType(interceptionObject);  
  3.             if (isNextCallShouldNotBeMocked(type)) {  
  4.                 MockRepository.putAdditionalState(MockGateway.DONT_MOCK_NEXT_CALL, true);  
  5.             }  
  6.         }  

 

猜你喜欢

转载自blog.csdn.net/a040600145/article/details/54587920