單元測試與集成測試.md

LLT(Low Level Test)通常由開發(fā)人員自測,它包括單元測試(Unit Test)委可、集成測試(Integration Test)、模塊系統(tǒng)測試(Module System Test)腊嗡、系統(tǒng)集成測試(BBIT)着倾,一般我們最關(guān)注的是UT(單元測試)和IT(集成測試)。

測試替身

Test Double(測試替身)包含了dummy, fake, mock, stub, spy 五種不同的類型燕少,這里我們引用Martin Fowler的經(jīng)典論述:

  • Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.
    Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).
  • Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test.
  • Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.
  • Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

簡單總結(jié)一下:

  • Dummy:被用來僅僅作為填充參數(shù)列表的對象卡者,實際上不會用到它們,對測試結(jié)果也沒有任何影響棺亭;
  • Fake:對一些系統(tǒng)進行裁剪之后形成的可運行的一套實現(xiàn)虎眨,跟源系統(tǒng)相比有一些(甚至很大)區(qū)別,不能上生產(chǎn)環(huán)境镶摘,但是作為測試使用非常適合嗽桩,能提前暴露很多問題,例如一個內(nèi)存版的數(shù)據(jù)庫凄敢;
  • Stub:為被測試對象提供數(shù)據(jù)碌冶,沒有任何行為,往往是測試對象依賴關(guān)系的上游涝缝;
  • Spy:被依賴對象的代理扑庞,行為往往由被代理的真實對象提供,代理的目的是為了斷言程序運行的正確性拒逮。比如我們針對一個發(fā)郵件服務(wù)做 spy罐氨,調(diào)用結(jié)束后,需要看下調(diào)用了幾次滩援,這時候就用到了這份信息栅隐;
  • Mock:重點在于 expectation!也就是說,我們對于這次調(diào)用在遇到各種情況時應(yīng)該怎么處理租悄,提前指定好規(guī)范)谨究。

其中,Dummy 和 Fake 好理解泣棋,一個是沒啥用胶哲,只是占位符,另一個是基本上啥都能干潭辈,比真實的系統(tǒng)差點意思鸯屿,但基本上能覆蓋大部分場景。而對于 spy萎胰,通常我們不太區(qū)分它和 stub碾盟,可以一起理解。
那么問題來了技竟,Mock 說的是你要明確你對每次調(diào)用的 expectation冰肴,需要寫代碼來指明什么情況下要怎么做,而 Fake 好像也是這個意思榔组,區(qū)別在于這個代碼可能不用你寫(因為開源社區(qū)有一些現(xiàn)成可用的)熙尉。那么它們根本區(qū)別是什么呢?
把握住這三點即可:

  • Fake => working implementations
  • Mock => predefined behavior
  • Stub => predefined values

In state verification you have the object under testing perform a certain operation, after being supplied with all necessary collaborators. When it ends, you examine the state of the object and/or the collaborators, and verify it is the expected one.
In behaviour verification, on the other hand, you specify exactly which methods are to be invoked on the collaboratos by the SUT, thus verifying not that the ending state is correct, but that the sequence of steps performed was correct.

Mock 和 Stub 的區(qū)別在于搓扯,前者是行為检痰,后者是狀態(tài)∠峭疲基于 Mock 做的是 behavior-based verification, 基于 Stub 做的是 State-based verification铅歼,這跟驗證的方法有關(guān)。而 Mock 和 Fake 的區(qū)別在于换可,你在寫單測的時候椎椰,需不需要構(gòu)建出一個 working implementation,還是說只要預(yù)設(shè)一些行為的響應(yīng)即可沾鳄。

當(dāng)然啦慨飘,這些概念都是一些陽春白雪的東西,實際工作中译荞,還是需要適當(dāng)接地氣一些瓤的,比如:跟普通碼農(nóng)打交道的時候,說Mock就夠了吞歼,跟普通測試人員就說”打樁“圈膏。

常用工具

  • JUnit5 + Hamcrest + Mockito
    在面向Spring編程的年代,這就是最佳組合拳篙骡,其他諸如TestNG本辐、PowerMock等等桥帆,了解一下就好了医增,畢竟學(xué)習(xí)成本擺在那里慎皱。

  • MockServer

        <dependency>
            <groupId>org.mock-server</groupId>
            <artifactId>mockserver-netty</artifactId>
            <version>5.15.0</version>
        </dependency>

MockServer就是上文提到的Stub,使用場景舉例:模擬一個微信公眾號的后臺響應(yīng)叶骨。

  • Embedded Redis
        <dependency>
            <groupId>it.ozimov</groupId>
            <artifactId>embedded-redis</artifactId>
            <version>0.7.3</version>
        </dependency>

這是一個典型的Fake茫多,能夠?qū)崿F(xiàn)基本的Redis操作,但是某些高階特性忽刽,比如Stream還是無法實現(xiàn)天揖。

  • Wix Embedded MySQL
        <dependency>
            <groupId>com.wix</groupId>
            <artifactId>wix-embedded-mysql</artifactId>
            <version>4.6.2</version>
        </dependency>

比H2強大不少,可以指定MySQL版本跪帝,5.7非常好用今膊,8.0.x貌似有bug,推薦MariaDB4j伞剑。

  • MariaDB4j
        <dependency>
            <groupId>ch.vorburger.mariaDB4j</groupId>
            <artifactId>mariaDB4j-springboot</artifactId>
            <version>3.0.1</version>
            <scope>test</scope>
        </dependency>

又一個非常好用的一個Fake斑唬,目前默認數(shù)據(jù)庫版本是10.2.11,與Flyway等數(shù)據(jù)庫工具配合使用時需要注意版本支持情況黎泣,推薦使用8.5.x版本恕刘。

  • Test Containers
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>testcontainers</artifactId>
            <version>1.19.1</version>
        </dependency>
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>mysql</artifactId>
            <version>1.19.1</version>
        </dependency>

基于Docker鏡像,可以實現(xiàn)各種Fake抒倚,有興趣的童鞋可以自行了解下褐着。

  • Flapdoodle Embedded MongoDB
        <dependency>
            <groupId>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo.spring31x</artifactId>
            <version>4.9.3</version>
        </dependency>

MongoDB的一個老牌Fake了,注意區(qū)分2x和3x版本托呕。

知識擴展

  • Unit test: Specify and test one point of the contract of single method of a class. This should have a very narrow and well defined scope. Complex dependencies and interactions to the outside world are stubbed or mocked.

  • Integration test: Test the correct inter-operation of multiple subsystems. There is whole spectrum there, from testing integration between two classes, to testing integration with the production environment.

  • Smoke test (aka sanity check): A simple integration test where we just check that when the system under test is invoked it returns normally and does not blow up.

    • Smoke testing is both an analogy with electronics, where the first test occurs when powering up a circuit (if it smokes, it's bad!)...
    • ... and, apparently, with plumbing, where a system of pipes is literally filled by smoke and then checked visually. If anything smokes, the system is leaky.
  • Regression test: A test that was written when a bug was fixed. It ensures that this specific bug will not occur again. The full name is "non-regression test". It can also be a test made prior to changing an application to make sure the application provides the same outcome

  • Acceptance test: Test that a feature or use case is correctly implemented. It is similar to an integration test, but with a focus on the use case to provide rather than on the components involved.

  • System test: Tests a system as a black box. Dependencies on other systems are often mocked or stubbed during the test (otherwise it would be more of an integration test).

  • Pre-flight check: Tests that are repeated in a production-like environment, to alleviate the 'builds on my machine' syndrome. Often this is realized by doing an acceptance or smoke test in a production like environment.

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末项郊,一起剝皮案震驚了整個濱河市馅扣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呆抑,老刑警劉巖岂嗓,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鹊碍,居然都是意外死亡厌殉,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門侈咕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來公罕,“玉大人,你說我怎么就攤上這事耀销∥空眨” “怎么了澄干?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵葵诈,是天一觀的道長。 經(jīng)常有香客問我掌腰,道長,這世上最難降的妖魔是什么张吉? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任齿梁,我火速辦了婚禮,結(jié)果婚禮上肮蛹,老公的妹妹穿的比我還像新娘勺择。我一直安慰自己,他們只是感情好伦忠,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布省核。 她就那樣靜靜地躺著,像睡著了一般昆码。 火紅的嫁衣襯著肌膚如雪气忠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天未桥,我揣著相機與錄音笔刹,去河邊找鬼。 笑死冬耿,一個胖子當(dāng)著我的面吹牛舌菜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播亦镶,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼日月,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了缤骨?” 一聲冷哼從身側(cè)響起爱咬,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绊起,沒想到半個月后精拟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡虱歪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年蜂绎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笋鄙。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡师枣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出萧落,到底是詐尸還是另有隱情践美,我是刑警寧澤洗贰,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站陨倡,受9級特大地震影響敛滋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜玫膀,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一矛缨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧帖旨,春花似錦、人聲如沸灵妨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泌霍。三九已至货抄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間朱转,已是汗流浹背蟹地。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留藤为,地道東北人怪与。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像缅疟,于是被迫代替她去往敵國和親分别。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容