国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

淺談jmockit中mock機制的實現(xiàn)

lijy91 / 690人閱讀

摘要:看到的函數(shù)返回類型,估計就是在這里實現(xiàn)了字節(jié)碼的轉(zhuǎn)換,然后返回了新的被掉包的文件了。雖然是門靜態(tài)類型語言,不過幸虧有字節(jié)碼和作為中間層,使得實現(xiàn)起來相對容易。

最近在工作中寫單元測試的時候,有使用到j(luò)mockit來mock無關(guān)對象。

在jmockit中,你可以使用MockUp來創(chuàng)建一個“fake”的實例,對某個方法指定自己的實現(xiàn),而不是調(diào)用實際的方法。

對于接口類型,需要這樣調(diào)用:

@Mocked
private SomeInterface mockInstance;

mockInstance = new MockUp() {
    ...
}.getMockInstance();

這個倒沒有什么古怪的。估計又是使用了java.reflect.Proxy。這個技巧在很多Java框架中用到,比如Spring AOP對于接口類型的實現(xiàn),就是通過Proxy來混入攔截器實現(xiàn)的。

但是,對于其他類型的調(diào)用,就比較奇怪了:

@Mocked
private SomeProxy mockInstance;

new MockUp() {
    @Mock
    public int doSth() {
        return 1;
    }
};

mockInstance.doSth(); // return 1

new出來的對象,如果沒有賦值給新的變量,應(yīng)該是隨著GC風飄云散了。可就是在我的眼皮底下,mockInstance就這樣被掉包了。

Spring AOP中,對于非接口類型,是通過CGLIB魔改字節(jié)碼來實現(xiàn)攔截器注入的。所以我估計這個也是一樣的道理。不過令人想不通的是,jmockit到底是什么時候進行移花接木的?沒看到注入的地方啊……

只能通過看代碼來揭秘了。先從MockUp的構(gòu)造函數(shù)開始吧。

// MockUp.java
@Nonnull
private Class redefineClassOrImplementInterface(@Nonnull Class classToMock)
{
  if (classToMock.isInterface()) {
     return createInstanceOfMockedImplementationClass(classToMock, mockedType);
  }

  Class realClass = classToMock;

  if (isAbstract(classToMock.getModifiers())) {
     classToMock = new ConcreteSubclass(classToMock).generateClass();
  }

  classesToRestore = redefineMethods(realClass, classToMock, mockedType);
  return classToMock;
}

對于非接口類型,調(diào)用了redefineMethods來定義一個仿版。順著redefineMethods找下去,終于發(fā)現(xiàn)了jmockit的“作案手法”。

// MockClassSetup.java
@Nullable
private byte[] modifyRealClass(@Nonnull Class classToModify)
{
  if (rcReader == null) {
     rcReader = createClassReaderForRealClass(classToModify);
  }

  MockupsModifier modifier = new MockupsModifier(rcReader, classToModify, mockUp, mockMethods);
  rcReader.accept(modifier, SKIP_FRAMES);

  return modifier.wasModified() ? modifier.toByteArray() : null;
}

看到byte[]的函數(shù)返回類型,估計就是在這里實現(xiàn)了字節(jié)碼的轉(zhuǎn)換,然后返回了新的被掉包的class文件了。沿著MockupsModifier看下去,可以看到j(luò)mockit是用ASM來改動原來的實現(xiàn)(具體見external.asm這個包,我就沒有細看了)。

眾所周知,Java代碼先是編譯成class文件,然后由JVM加載運行的。圍繞JVM這一中間層,各種有趣的技術(shù)應(yīng)運而生。比如各種類加載器,可以動態(tài)地去加載同名的類的不同實現(xiàn)(不同的class文件)。還有各種魔改class文件的手段,在原來的實現(xiàn)中注入自己的代碼,像ASM、javassist、GCLIB,等等。jmockit就是應(yīng)用ASM來修改原來的class文件,用mocked的實現(xiàn)掉包原來的代碼。因為MockUp的構(gòu)造已經(jīng)觸發(fā)了“貍貓換太子”的幕后行為,所以這里就不用把new出來的東西賦值給具體變量了。

還有一個問題。我們雖然弄明白了jmockit的作案手法,可是還沒有找到掉包現(xiàn)場呢!即使現(xiàn)在jmockit已經(jīng)持有了被篡改后的字節(jié)碼,可它又是怎么替換呢?

繼續(xù)看下去,發(fā)現(xiàn)jmockit把修改后的字節(jié)碼存在StartUp.java里面了。轉(zhuǎn)過去會看到,jmockit這里用到了JDK6的一個新特性:動態(tài)Instrumentation。怪不得jmockit要求JDK版本知識在6以上。

關(guān)于動態(tài)Instrumentation,具體可以看下這篇文章:http://www.ibm.com/developerworks/cn/java/j-lo-jse61/
簡單來說,通過這一機制可以實現(xiàn)監(jiān)聽JVM加載類的事件,并在此之前運行自己的掛鉤方法。這么一來,掉包現(xiàn)場也找到了。

那jmockit怎么知道要監(jiān)聽哪些類呢?前面可以看到,需要Mock的類上,要添加Mocked注解。所以jmockit編寫了一些跟主流測試框架集成的代碼,在測試運行的時候獲取帶該注解的類。這樣就知道要監(jiān)聽的目標了。

總結(jié)一下:jmockit先通過Mocked注解標記需要Mock掉的類。然后調(diào)用new MockUp去創(chuàng)建修改后的class文件。在JVM運行的時候,通過JDK6之后的動態(tài)Instrumentation特性監(jiān)聽類加載事件,并在目標類加載之前移花接木,用魔改后的字節(jié)碼換掉真貨。雖然Java是門靜態(tài)類型語言,不過幸虧有字節(jié)碼和JVM作為中間層,使得mock實現(xiàn)起來相對容易。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/64488.html

相關(guān)文章

  • 靜態(tài)方法,mock 還是不 mock,這是個問題

    摘要:單元測試中是否要靜態(tài)方法,一直爭論不休,網(wǎng)上有一個一個又一個的討論,各種意見都有。真要用來靜態(tài)方法,一般都是結(jié)合使用。等工具不支持靜態(tài)方法,原理上是因為它們都是基于的,只能通過創(chuàng)建子類或?qū)崿F(xiàn)接口的方式去。什么靜態(tài)方法構(gòu)造函數(shù),隨時隨地想就。 王者 Mockito 不知從何時開始,Mockito 成了 Java 的單元測試框架王者,目前(2019年7月)Github 上 star 數(shù)直逼...

    waterc 評論0 收藏0
  • 2021年軟件測試工具總結(jié)——單元測試工具

    摘要:單元測試框架作為的標準庫,是其他單元測試框架的基礎(chǔ)。可以和和配合使用編寫單元測試。官網(wǎng)地址單元測試覆蓋率工具單元測試中還需要用到代碼覆蓋率工具。代碼覆蓋率統(tǒng)計工具用來發(fā)現(xiàn)沒有被測試覆蓋的代碼,完善單元測試的覆蓋率。 在應(yīng)用程序中,單元是具有一個或多個輸入和單個輸出的軟件中最小可測試部分。單元...

    qingshanli1988 評論0 收藏0
  • 淺談前端mock

    摘要:引言前端開發(fā)經(jīng)常需要等待后端的接口,嚴重影響了開發(fā)效率,我們一般采用方式來避免這個問題。可能會涉及到門技術(shù),分別是服務(wù)端技術(shù)隨機生成特定格式數(shù)據(jù)的技術(shù)請求轉(zhuǎn)發(fā)請求攔截。 引言 前端開發(fā)經(jīng)常需要等待后端的接口,嚴重影響了開發(fā)效率,我們一般采用mock方式來避免這個問題。本人參考了大量文章,結(jié)合自己的經(jīng)驗,給出自己在mock上的一些理解。 1. 原理 何為mock,我認為mock主要就是通...

    elina 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<