Mockito详细介绍
文章目錄
- 簡介
- mock、stub、spy
- 使用
- 引入
- 代碼
- 原理
- 框架設計
- mock
- 創建MockHandler
- 創建mock對象
- when
- OngoingStubbing
- verify
- Handler
- MockingProgress
- 匹配器
- ArgumentCaptor
- CapturingMatcher
- 參考
- bytebuddy
- Mockito生成的Class
- Class說明
- MockMethodInterceptor
簡介
測試驅動的開發(Test Driven Design, TDD)要求我們先寫單元測試,再寫實現代碼。在寫單元測試的過程中,一個很普遍的問題是,要測試的類會有很多依賴,這些依賴的類/對象/資源又會有別的依賴,從而形成一個大的依賴樹,要在單元測試的環境中完整地構建這樣的依賴,是一件很困難的事情。
所幸,我們有一個應對這個問題的辦法:Mock。簡單地說就是對測試的類所依賴的其他類和對象,進行mock - 構建它們的一個假的對象,定義這些假對象上的行為,然后提供給被測試對象使用。被測試對象像使用真的對象一樣使用它們。用這種方式,我們可以把測試的目標限定于被測試對象本身,就如同在被測試對象周圍做了一個劃斷,形成了一個盡量小的被測試目標。Mock的框架有很多,最為知名的一個是Mockito,這是一個開源項目,使用廣泛。
mock、stub、spy
mock是構造假對象。stub也就是常說的打樁,針對某些入參返回自定義數據,即把調用與返回值進行綁定。;mock也就是mock類,默認返回空數據(一般是null)。
spy對真實對象進行監控。
使用
引入
<!--測試依賴--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><version>2.2.2.RELEASE</version></dependency><!-- https://mvnrepository.com/artifact/org.mockito/mockito-core --><dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>2.7.22</version><scope>test</scope></dependency>代碼
原理
以2.7.22的源碼。
框架設計
Mock對象這件事情,本質上是一個Proxy模式的應用。Proxy模式說的是,在一個真實對象前面,提供一個proxy對象,所有對真實對象的調用,都先經過proxy對象,然后由proxy對象根據情況,決定相應的處理,它可以直接做一個自己的處理,也可以再調用真實對象對應的方法。
Java本身提供了構建Proxy對象的API:Java Dynamic Proxy API,而Mockito是用**Cglib**來實現的。
Mokito利用Cglib為Mock的接口的所有方法都做了Mock實現。所有的方法調用都經過了proxy對象,proxy對象可以記錄所有調用的信息,供驗證的時候去檢查。當when()方法被調用時,調用proxy的對應的方法,返回的不是某個值,而是方法調用的信息(invocationMatcher 對象),在調用thenReturn()方法時,把調用信息和返回值進行了綁定。則后面調用時,會根據調用信息(invocationMatcher 對象),找到綁定的值,直接返回。
public interface InvocationListener {void reportInvocation(MethodInvocationReport methodInvocationReport); }public interface MethodInvocationReport {DescribedInvocation getInvocation();Object getReturnedValue();Throwable getThrowable();boolean threwException();String getLocationOfStubbing(); }public class NotifiedMethodInvocationReport implements MethodInvocationReport {private final Invocation invocation;private final Object returnedValue;private final Throwable throwable; }mock
Mockito類中有幾個mock函數的重載,最終都會調到mock(Class<T> classToMock, MockSettings mockSettings),接受一個class類型與一個mockSettings,class就是我們需要mock對象的類型,而mockSettings則記錄著此次mock的一些信息。mock的行為實則轉交個MockitoCore:
MOCKITO_CORE.mock(classToMock, mockSettings) //===MockitoCore public <T> T mock(Class<T> typeToMock, MockSettings settings) {if (!MockSettingsImpl.class.isInstance(settings)) {throw new IllegalArgumentException("Unexpected implementation of '" + settings.getClass().getCanonicalName() + "'\n" + "At the moment, you cannot provide your own implementations of that class.");}MockSettingsImpl impl = MockSettingsImpl.class.cast(settings);MockCreationSettings<T> creationSettings = impl.confirm(typeToMock);//MockUtil的createMock方法T mock = createMock(creationSettings);mockingProgress().mockingStarted(mock, creationSettings);return mock;}在MockUtil中則作了兩件非常關鍵的事情:
//===MockUtilpublic static <T> T createMock(MockCreationSettings<T> settings) {//創建MockHandlerMockHandler mockHandler = createMockHandler(settings);//MOCKT mock = mockMaker.createMock(settings, mockHandler);Object spiedInstance = settings.getSpiedInstance();if (spiedInstance != null) {new LenientCopyTool().copyToMock(spiedInstance, mock);}return mock;}創建MockHandler
MockHandler對象的實例是InvocationNotifierHandler類型,但它只是負責對外的包裝,內部實際起作用的是MockHandlerImpl,承載了Mockito的主要邏輯。InvocationNotifierHandler 主要提供了事件通知功能。
public class MockHandlerFactory {public static <T> InternalMockHandler<T> createMockHandler(MockCreationSettings<T> settings) {//內部Handler是MockHandlerImplInternalMockHandler<T> handler = new MockHandlerImpl<T>(settings);//nullResultGuardian是個代理類,用于處理返回值為null或者原生類型的情況。InternalMockHandler<T> nullResultGuardian = new NullResultGuardian<T>(handler);return new InvocationNotifierHandler<T>(nullResultGuardian, settings);} } class InvocationNotifierHandler<T> implements MockHandler, InternalMockHandler<T> {private final List<InvocationListener> invocationListeners;private final InternalMockHandler<T> mockHandler;public Object handle(Invocation invocation) throws Throwable {try {Object returnedValue = mockHandler.handle(invocation);//通知:調用事件。notifyMethodCall(invocation, returnedValue);return returnedValue;} catch (Throwable t){notifyMethodCallException(invocation, t);throw t;}}private void notifyMethodCall(Invocation invocation, Object returnValue) {for (InvocationListener listener : invocationListeners) {try {listener.reportInvocation(new NotifiedMethodInvocationReport(invocation, returnValue));} catch(Throwable listenerThrowable) {throw invocationListenerThrewException(listener, listenerThrowable);}}}創建mock對象
創建mock對象使用MockMaker。MockMaker是個接口,用于創建mock對象,通過插件注冊機制發現MockMaker實例。
private static final MockMaker mockMaker = Plugins.getMockMaker();MockMaker有以下幾個子類
- ClassCreatingMockMaker:接口,通過生成類創建Mock對象
- ByteBuddyMockMaker:內部使用SubclassByteBuddyMockMaker 構造mock Class。
- SubclassByteBuddyMockMaker:通過子類方式構造Class。
- InlineByteBuddyMockMaker:使用Java instrumentation API mock Class。
這個Instantiator也是一個接口,它有兩個實現,一是ObjenesisInstantiator,另外一個是ConstructorInstantiator, 默認情況下,都是在使用 ObjenesisInstantiator。
objenesis是一個框架,可以根據不同的平臺選 擇不同的方法來new對象。
when
//=== Mockitopublic static <T> OngoingStubbing<T> when(T methodCall) {return MOCKITO_CORE.when(methodCall);} //MOCKITO_COREpublic <T> OngoingStubbing<T> when(T methodCall) {MockingProgress mockingProgress = mockingProgress();mockingProgress.stubbingStarted();@SuppressWarnings("unchecked")OngoingStubbing<T> stubbing = (OngoingStubbing<T>) mockingProgress.pullOngoingStubbing();if (stubbing == null) {mockingProgress.reset();throw missingMethodInvocation();}return stubbing;}OngoingStubbing
OngoingStubbing接口封裝了stub,用于保存調用對應的返回值以及異常。
public interface OngoingStubbing<T> {//設置返回值OngoingStubbing<T> thenReturn(T value);//設置連續返回的返回值。一次調用返回一個值。// Additional method helps users of JDK7+ to hide heap pollution / unchecked generics array creation warnings (on call site)@SuppressWarnings ({"unchecked", "varargs"})OngoingStubbing<T> thenReturn(T value, T... values);OngoingStubbing<T> thenThrow(Throwable... throwables);OngoingStubbing<T> thenThrow(Class<? extends Throwable> throwableType);// Additional method helps users of JDK7+ to hide heap pollution / unchecked generics array creation warnings (on call site)@SuppressWarnings ({"unchecked", "varargs"})OngoingStubbing<T> thenThrow(Class<? extends Throwable> toBeThrown, Class<? extends Throwable>... nextToBeThrown);OngoingStubbing<T> thenCallRealMethod();OngoingStubbing<T> thenAnswer(Answer<?> answer);OngoingStubbing<T> then(Answer<?> answer);<M> M getMock(); }verify
verify的基本使用形式是verify(mock).doSome(),verify有幾個重載函數,但最終都會掉到如下函數:
//MOCKITO_COREpublic <T> T verify(T mock, VerificationMode mode) {if (mock == null) {throw nullPassedToVerify();}if (!isMock(mock)) {throw notAMockPassedToVerify(mock.getClass());}MockingProgress mockingProgress = mockingProgress();VerificationMode actualMode = mockingProgress.maybeVerifyLazily(mode);mockingProgress.verificationStarted(new MockAwareVerificationMode(mock, actualMode, mockingProgress.verificationListeners()));return mock;}VerificationMode是對驗證信息的封裝,它是一個接口,含有verify函數。常用的never(). times(1)返回的都是Times類型,而Times類型就是VerificationMode的一種實現。
public interface VerificationMode {void verify(VerificationData data);VerificationMode description(String description); }通過以下靜態方法,可以構造VerificationMode
- atLeastOnce:至少進行一次驗證
- atLeast:允許至少進行x次驗證
- only
- times
- calls:允許順序進行non-greedy驗證
- noMoreInteractions
- atMost:至多進行x次驗證
- description
Handler
mockito對接口進行mock,針對mock對象的每個方法都生成了代碼,最終調用MockHandlerImpl的handle()方法。handler保存了MockSettingsImpl實例。MockSettingsImpl實例保存了mock對象的所有配置信息,包括接口信息,spy信息,stub等。
public interface MockHandler extends Serializable {Object handle(Invocation invocation) throws Throwable; }public interface InternalMockHandler<T> extends MockHandler {MockCreationSettings<T> getMockSettings();void setAnswersForStubbing(List<Answer<?>> answers);InvocationContainer getInvocationContainer(); }public class MockHandlerImpl<T> implements InternalMockHandler<T> {private static final long serialVersionUID = -2917871070982574165L;//調用容器InvocationContainerImpl invocationContainerImpl;//匹配器MatchersBinder matchersBinder = new MatchersBinder();//mock 設置信息private final MockCreationSettings<T> mockSettings; }Handler處理邏輯:
public Object handle(Invocation invocation) throws Throwable {//是否有Answer,如果有,則由Answer處理。if (invocationContainerImpl.hasAnswersForStubbing()) {// stubbing voids with doThrow() or doAnswer() styleInvocationMatcher invocationMatcher = matchersBinder.bindMatchers(mockingProgress().getArgumentMatcherStorage(),invocation);invocationContainerImpl.setMethodForStubbing(invocationMatcher);return null;}//Verify邏輯處理。獲取驗證模式。VerificationMode verificationMode = mockingProgress().pullVerificationMode();InvocationMatcher invocationMatcher = matchersBinder.bindMatchers(mockingProgress().getArgumentMatcherStorage(),invocation);mockingProgress().validateState();//verificationMode不為null,表示正在進行verify操作。if (verificationMode != null) {// We need to check if verification was started on the correct mock// - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138)//同一個mock對象,則驗證if (((MockAwareVerificationMode) verificationMode).getMock() == invocation.getMock()) {VerificationDataImpl data = createVerificationData(invocationContainerImpl, invocationMatcher);//驗證verificationMode.verify(data);return null;} else {//否則開始驗證。// this means there is an invocation on a different mock. Re-adding verification mode// - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138)mockingProgress().verificationStarted(verificationMode);}}// stub處理邏輯。invocationContainerImpl.setInvocationForPotentialStubbing(invocationMatcher);OngoingStubbingImpl<T> ongoingStubbing = new OngoingStubbingImpl<T>(invocationContainerImpl);mockingProgress().reportOngoingStubbing(ongoingStubbing);// look for existing answer for this invocationStubbedInvocationMatcher stubbedInvocation = invocationContainerImpl.findAnswerFor(invocation);notifyStubbedAnswerLookup(invocation, stubbedInvocation);if (stubbedInvocation != null) {stubbedInvocation.captureArgumentsFrom(invocation);return stubbedInvocation.answer(invocation);} else {Object ret = mockSettings.getDefaultAnswer().answer(invocation);DefaultAnswerValidator.validateReturnValueFor(invocation, ret);//====局部 mock,spy 處理邏輯// redo setting invocation for potential stubbing in case of partial// mocks / spies.// Without it, the real method inside 'when' might have delegated// to other self method and overwrite the intended stubbed method// with a different one. The reset is required to avoid runtime exception that validates return type with stubbed method signature.invocationContainerImpl.resetInvocationForPotentialStubbing(invocationMatcher);return ret;}}MockingProgress
MockingProgress用于控制mock的處理過程。通過ThreadLocal多線程并發控制。內部實現為MockingProgressImpl。 當when和verify時,通過獲取ThreadLocal獲取到線程中的MockingProgress實例。
public class ThreadSafeMockingProgress {private static final ThreadLocal<MockingProgress> MOCKING_PROGRESS_PROVIDER = new ThreadLocal<MockingProgress>() {@Overrideprotected MockingProgress initialValue() {return new MockingProgressImpl();}};private ThreadSafeMockingProgress() {}public final static MockingProgress mockingProgress() {return MOCKING_PROGRESS_PROVIDER.get();} } public class MockingProgressImpl implements MockingProgress {//參數匹配器存儲private final ArgumentMatcherStorage argumentMatcherStorage = new ArgumentMatcherStorageImpl();//stub,when調用時設置。report時重新設置。private OngoingStubbing<?> ongoingStubbing;//驗證模式。verify調用時設置。private Localized<VerificationMode> verificationMode;//進度:返回string。默認實現:LocationImplprivate Location stubbingInProgress = null;//驗證策略。默認直接返回參數private VerificationStrategy verificationStrategy;//listeners。mock 調用時設置。verify時從此復制。private final Set<MockitoListener> listeners = new LinkedHashSet<MockitoListener>(); }mock調用
public void mockingStarted(Object mock, MockCreationSettings settings) {//通知事件。for (MockitoListener listener : listeners) {if (listener instanceof MockCreationListener) {((MockCreationListener) listener).onMockCreated(mock, settings);}}//校驗成員validateMostStuff();}when調用
public void stubbingStarted() {validateState();//設置初始進度stubbingInProgress = new LocationImpl();}public void validateState() {validateMostStuff();//validate stubbing:if (stubbingInProgress != null) {Location temp = stubbingInProgress;stubbingInProgress = null;throw unfinishedStubbing(temp);}}private void validateMostStuff() {//State is cool when GlobalConfiguration is already loaded//this cannot really be tested functionally because I cannot dynamically mess up org.mockito.configuration.MockitoConfiguration classGlobalConfiguration.validate();if (verificationMode != null) {Location location = verificationMode.getLocation();verificationMode = null;throw unfinishedVerificationException(location);}getArgumentMatcherStorage().validateState();}when()方法會調用MockingProgress的pullOngoingStubbing()方法獲取OngoingStubbing。然后就可以通過OngoingStubbing設置stub的各種返回值。
public OngoingStubbing<?> pullOngoingStubbing() {OngoingStubbing<?> temp = ongoingStubbing;ongoingStubbing = null;return temp;}verify調用
//=== MockitoCorepublic <T> T verify(T mock, VerificationMode mode) {if (mock == null) {throw nullPassedToVerify();}if (!isMock(mock)) {throw notAMockPassedToVerify(mock.getClass());}MockingProgress mockingProgress = mockingProgress();//獲取驗證模式。VerificationMode actualMode = mockingProgress.maybeVerifyLazily(mode);mockingProgress.verificationStarted(new MockAwareVerificationMode(mock, actualMode, mockingProgress.verificationListeners()));return mock;}//=== MockingProgressImplpublic VerificationMode maybeVerifyLazily(VerificationMode mode) {return this.verificationStrategy.maybeVerifyLazily(mode);}//=== MockingProgressImpl//創建Listener容器。public Set<VerificationListener> verificationListeners() {final LinkedHashSet<VerificationListener> verificationListeners = new LinkedHashSet<VerificationListener>();for (MockitoListener listener : listeners) {if (listener instanceof VerificationListener) {verificationListeners.add((VerificationListener) listener);}}return verificationListeners;}//=== MockingProgressImpl//設置VerificationMode。public void verificationStarted(VerificationMode verify) {validateState();resetOngoingStubbing();verificationMode = new Localized(verify);}handle涉及
//=== MockingProgressImplpublic void reportOngoingStubbing(OngoingStubbing iOngoingStubbing) {this.ongoingStubbing = iOngoingStubbing;}匹配器
Mockito 2.1.0之后,匹配器與Hamcrest解耦,定義了ArgumentMatcher接口。在ArgumentMatchers定義了很多靜態方法,構造ArgumentMatcher實例。包路徑:ArgumentMatcherorg.mockito.internal.matchers
public interface ArgumentMatcher<T> {boolean matches(T argument); }靜態方法:
any, any, anyBoolean, anyByte, anyChar, anyCollection, anyCollectionOf, anyDouble, anyFloat, anyInt, anyIterable, anyIterableOf, anyList, anyListOf, anyLong, anyMap, anyMapOf, anyObject, anySet, anySetOf, anyShort, anyString, anyVararg, argThat, booleanThat, byteThat, charThat, contains, doubleThat, endsWith, eq, eq, eq, eq, eq, eq, eq, eq, eq, floatThat, intThat, isA, isNotNull, isNotNull, isNull, isNull, longThat, matches, matches, notNull, notNull, nullable, refEq, same, shortThat, startsWithArgumentCaptor
ArgumentCaptor是一個能夠捕獲參數值的特殊參數匹配器。在某些場景中,不光要對方法的返回值和調用進行驗證,同時需要驗證一系列交互后所傳入方法的參數。那么我們可以用參數捕獲器來捕獲傳入方法的參數進行驗證,看它是否符合我們的要求。
通過ArgumentCaptor對象的forClass(Class<T> clazz)方法來構建ArgumentCaptor對象。然后便可在驗證時對方法的參數進行捕獲,最后驗證捕獲的參數值。如果方法有多個參數都要捕獲驗證,那就需要創建多個ArgumentCaptor對象處理。
//用于保存捕獲的參數private final CapturingMatcher<T> capturingMatcher = new CapturingMatcher<T>();private ArgumentCaptor(Class<? extends T> clazz) {this.clazz = clazz;} public static <U,S extends U> ArgumentCaptor<U> forClass(Class<S> clazz) {return new ArgumentCaptor<U>(clazz);}ArgumentCaptor的Api
argument.capture() //捕獲方法參數 argument.getValue() //獲取方法參數值,如果方法進行了多次調用,它將返回最后一個參數值 argument.getAllValues() //方法進行多次調用后,返回多個參數值CapturingMatcher
public class CapturingMatcher<T> implements ArgumentMatcher<T>, CapturesArguments, VarargMatcher, Serializable { //保存捕獲的參數private final LinkedList<Object> arguments = new LinkedList<Object>();}參考
官網:https://site.mockito.org/ , https://github.com/mockito/mockito,
匹配器(Matcher):https://javadoc.io/static/org.mockito/mockito-core/3.9.0/org/mockito/Matchers.html
bytebuddy
Byte Buddy是致力于解決字節碼操作和 instrumentation API 的復雜性的開源框架。Byte Buddy 所聲稱的目標是將顯式的字節碼操作隱藏在一個類型安全的領域特定語言背后。通過使用 Byte Buddy,任何熟悉 Java 編程語言的人都有望非常容易地進行字節碼操作。
Byte Buddy是一個較高層級的抽象的字節碼操作工具,相較于ASM而言。其實吧,Byte Buddy 本身也是基于 ASM API 實現的。
Mockito生成的Class
可以使用JVM的HSDB工具來查看mock生成的Class。Mockito生成的class的名稱格式為:
codegen.java.util.List$MockitoMock$2104292027 @0x00000007c0235128以codegen開頭,后跟interface,然后是MockitoMock。
Class說明
package codegen.java.util; //package根據mock的接口確定。 //以下是引入mockito生成的輔助類。 import codegen.java.util.List.MockitoMock.2104292027.auxiliary.7DJ06WP7; import codegen.java.util.List.MockitoMock.2104292027.auxiliary.KpK3ZEDf; import codegen.java.util.List.MockitoMock.2104292027.auxiliary.NJCNn1rp; import codegen.java.util.List.MockitoMock.2104292027.auxiliary.PkMnkkjK; import codegen.java.util.List.MockitoMock.2104292027.auxiliary.WPMlpJ7S; import codegen.java.util.List.MockitoMock.2104292027.auxiliary.dAVk5zvB; import codegen.java.util.List.MockitoMock.2104292027.auxiliary.pP7UZY0a; import codegen.java.util.List.MockitoMock.2104292027.auxiliary.wMxmFLt1; import codegen.java.util.List.MockitoMock.2104292027.auxiliary.yOBrfhSk; //繼承了List,MockAccess public class List$MockitoMock$2104292027 implements List, MockAccess {private static final long serialVersionUID = 42L;//MockAccessprivate MockMethodInterceptor mockitoInterceptor;public List$MockitoMock$2104292027() {}//List接口的方法。static {cachedValue$FPJFWYZr$gs4cee0 = List.class.getMethod("remove", Integer.TYPE);cachedValue$FPJFWYZr$77a53p0 = List.class.getMethod("lastIndexOf", Object.class);cachedValue$FPJFWYZr$479u1c1 = List.class.getMethod("size");cachedValue$FPJFWYZr$pa58dn1 = List.class.getMethod("toArray");cachedValue$FPJFWYZr$2v2l442 = List.class.getMethod("retainAll", Collection.class);cachedValue$FPJFWYZr$itsld03 = List.class.getMethod("iterator");cachedValue$FPJFWYZr$tm4die2 = List.class.getMethod("indexOf", Object.class);cachedValue$FPJFWYZr$idijvh3 = List.class.getMethod("subList", Integer.TYPE, Integer.TYPE);cachedValue$FPJFWYZr$ialm821 = List.class.getMethod("spliterator");cachedValue$FPJFWYZr$vv27a83 = List.class.getMethod("listIterator", Integer.TYPE);cachedValue$FPJFWYZr$4cscpe1 = Object.class.getMethod("toString");cachedValue$FPJFWYZr$pqjhh82 = List.class.getMethod("addAll", Integer.TYPE, Collection.class);cachedValue$FPJFWYZr$bp48n33 = List.class.getMethod("clear");cachedValue$FPJFWYZr$8o98bj1 = List.class.getMethod("containsAll", Collection.class);cachedValue$FPJFWYZr$3um2h43 = List.class.getMethod("removeAll", Collection.class);cachedValue$FPJFWYZr$ascqpd0 = Iterable.class.getMethod("forEach", Consumer.class);cachedValue$FPJFWYZr$5p89p02 = List.class.getMethod("set", Integer.TYPE, Object.class);cachedValue$FPJFWYZr$g7qoll1 = List.class.getMethod("sort", Comparator.class);cachedValue$FPJFWYZr$6epee82 = List.class.getMethod("addAll", Collection.class);cachedValue$FPJFWYZr$ivs3a83 = List.class.getMethod("listIterator");cachedValue$FPJFWYZr$bbf8080 = Collection.class.getMethod("parallelStream");cachedValue$FPJFWYZr$3us6oc3 = List.class.getMethod("add", Integer.TYPE, Object.class);cachedValue$FPJFWYZr$61en0h1 = List.class.getMethod("replaceAll", UnaryOperator.class);cachedValue$FPJFWYZr$7m9oaq0 = Object.class.getDeclaredMethod("clone");cachedValue$FPJFWYZr$4i8d8f1 = Collection.class.getMethod("stream");cachedValue$FPJFWYZr$v9lk1j0 = List.class.getMethod("remove", Object.class);cachedValue$FPJFWYZr$q0m7l61 = List.class.getMethod("contains", Object.class);cachedValue$FPJFWYZr$eqbjn92 = List.class.getMethod("toArray", Object[].class);cachedValue$FPJFWYZr$2ff4l01 = List.class.getMethod("get", Integer.TYPE);cachedValue$FPJFWYZr$aqin4c0 = Collection.class.getMethod("removeIf", Predicate.class);cachedValue$FPJFWYZr$sgg2351 = List.class.getMethod("add", Object.class);cachedValue$FPJFWYZr$dc8ju02 = List.class.getMethod("isEmpty");}//所有的方法實際都調用了DispatcherDefaultingToRealMethod.interceptAbstract。傳入mockitoInterceptor//方法的Method對象。以及參數。public void add(int var1, Object var2) {DispatcherDefaultingToRealMethod.interceptAbstract(this, this.mockitoInterceptor, (Object)null, cachedValue$FPJFWYZr$3us6oc3, new Object[]{var1, var2});}//父類方法public void replaceAll(UnaryOperator var1) {DispatcherDefaultingToRealMethod.interceptSuperCallable(this, this.mockitoInterceptor, cachedValue$FPJFWYZr$61en0h1, new Object[]{var1}, new WPMlpJ7S(this, var1));}... ...//MockAccess接口相關public void setMockitoInterceptor(MockMethodInterceptor var1) {this.mockitoInterceptor = var1;}public MockMethodInterceptor getMockitoInterceptor() {return this.mockitoInterceptor;}MockMethodInterceptor
interceptAbstract方法調用了MockMethodInterceptor的doIntercept方法。
//DispatcherDefaultingToRealMethodpublic static Object interceptAbstract(@This Object mock,@FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor,@StubValue Object stubValue,@Origin Method invokedMethod,@AllArguments Object[] arguments) throws Throwable {if (interceptor == null) {return stubValue;}return interceptor.doIntercept(mock,invokedMethod,arguments,InterceptedInvocation.SuperMethod.IsIllegal.INSTANCE);}//DispatcherDefaultingToRealMethodpublic static Object interceptSuperCallable(@This Object mock,@FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor,@Origin Method invokedMethod,@AllArguments Object[] arguments,@SuperCall(serializableProxy = true) Callable<?> superCall) throws Throwable {if (interceptor == null) {return superCall.call();}return interceptor.doIntercept(mock,invokedMethod,arguments,new InterceptedInvocation.SuperMethod.FromCallable(superCall));} //MockMethodInterceptorObject doIntercept(Object mock,Method invokedMethod,Object[] arguments,InterceptedInvocation.SuperMethod superMethod) throws Throwable {return doIntercept(mock,invokedMethod,arguments,superMethod,new LocationImpl());}Object doIntercept(Object mock,Method invokedMethod,Object[] arguments,InterceptedInvocation.SuperMethod superMethod,Location location) throws Throwable {//調用InternalMockHandler的handle方法return handler.handle(//構造InterceptedInvocationnew InterceptedInvocation(mock,createMockitoMethod(invokedMethod),arguments,superMethod,location,SequenceNumber.next()));}總結
以上是生活随笔為你收集整理的Mockito详细介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gitlab-ci详细说明
- 下一篇: K8S之HELM详细介绍