BDD旨在解決具體問題,幫助開發(fā)人員確定應(yīng)該測(cè)試些什么。它提供了一個(gè)DSL( Domain-specific language,域特定語言)鼓勵(lì)開發(fā)者弄清楚他們的需求,并且它引入了一個(gè)通用語言幫助你輕易理解測(cè)試的目的。
Q:我應(yīng)該測(cè)試什么?
A:測(cè)試你對(duì)象的行為方式。
BDD框架
Swift專用的BDD框架:
對(duì)比:
Cedar捆綁了匹配和置換,還包含了額外的配置功能:集中測(cè)試,提供了反向配置能力,但它用了一點(diǎn)黑客技術(shù)才能與XCTest集成,所以如果XCTest改變了的話,Cedar容易失效。
Kiwi同樣捆綁了匹配模塊以及stubs和mocks,但缺乏像 Cedar一樣的可配置性功能。
Specta缺少匹配,也沒有mocks或者stubs,但它緊密地與XCTest結(jié)合在一起并且提供了近似Cedar的可配置性的能力。
依賴注入(Dependency Injection)
原文:依賴注入
DI本身是在彰顯一個(gè)更高層面的概念:代碼組成了模塊,模塊拼接構(gòu)建成了應(yīng)用本身。
-
構(gòu)造器注入:構(gòu)造器注入,即將某個(gè)依賴對(duì)象傳入到構(gòu)造器中 (在 Objective- C中指 designated 初始化方法) 并存儲(chǔ)起來,以便在后續(xù)過程中使用;
注意:盡管 Objective-C 本身沒有所謂的構(gòu)造器而是使用初始化方法,但因?yàn)闃?gòu)造器注入是 DI 的標(biāo)準(zhǔn)概念,放到各種語言中也是普遍適用的,所以還是準(zhǔn)備用構(gòu)造器注入這個(gè)詞來代指初始化注入。
-
屬性注入:采用屬性賦值方式,以便在后續(xù)過程中使用; -
方法注入:如果依賴對(duì)象只在某一個(gè)方法中被使用,則可以利用方法參數(shù)做注入; -
環(huán)境上下文:當(dāng)通過一個(gè)類方法 (例如單例) 來訪問依賴對(duì)象時(shí),在單元測(cè)試中可以通過兩種方式來控制依賴對(duì)象。- 如果可以控制單例本身,則可以通過公開其屬性來控制其狀態(tài);
- 如果上述方式無效或者所操作的單例不歸自己管理,此時(shí)就該運(yùn)用swizzling了:直接替換類方法,讓其返回你所期望的返回值。
寫測(cè)試
測(cè)試用例使我們的代碼質(zhì)量變得可靠,同時(shí)讓我們能夠放心地重構(gòu)或者修改代碼,并保證我們的修改沒有破壞其他部分。
原文:糟糕的測(cè)試
可以根據(jù)Given-When-Then模式來組織我們的測(cè)試用例。
寫測(cè)試的時(shí)候問自己兩個(gè)問題:
- “如果我修改了我的生產(chǎn)代碼,測(cè)試是會(huì)失敗 (還是通過) 呢?”
- “那是一個(gè)讓測(cè)試失敗 (或者通過) 的好的理由么?”
測(cè)試的基本準(zhǔn)則(F.I.R.S.T.)
- 很快速(Fast) —— 測(cè)試應(yīng)該能夠被經(jīng)常執(zhí)行。
- 能隔離(Isolated) —— 測(cè)試本身不能依賴于外部因素或者其他測(cè)試的結(jié)果。
- 可重復(fù)(Repeatable) —— 每次運(yùn)行測(cè)試都應(yīng)該產(chǎn)生相同的結(jié)果。
- 帶自檢(Self-verifying) —— 測(cè)試應(yīng)該包括斷言,不需要人為干預(yù)。
- 夠及時(shí)(Timely) —— 測(cè)試應(yīng)該和生產(chǎn)代碼一同書寫。
注意:測(cè)試中一個(gè)最重要的關(guān)鍵點(diǎn)是降低未來的變化所帶來的成本,不要將測(cè)試和實(shí)現(xiàn)細(xì)節(jié)耦合在一起。
-
不要測(cè)試私有方法:可以進(jìn)行置換測(cè)試 -
不要 Stub 私有方法:stub 私有方法將會(huì)使程序難以調(diào)試 -
不要 Stub 外部庫:第三方代碼不應(yīng)該在你的測(cè)試中直接出現(xiàn)。 正確地 Stub 依賴-
不要測(cè)試構(gòu)造函數(shù):構(gòu)造函數(shù)定義的是實(shí)現(xiàn)細(xì)節(jié),你不應(yīng)該測(cè)試構(gòu)造函數(shù)。
置換測(cè)試: Mock, Stub etc.
用一些模擬代碼替換你的實(shí)際代碼來編寫一些測(cè)試用例
原文:置換測(cè)試: Mock, Stub 和其他
mock測(cè)試就是在測(cè)試過程中,對(duì)于某些不容易構(gòu)造或者不容易獲取的對(duì)象,用一個(gè)虛擬的對(duì)象來創(chuàng)建以便測(cè)試的測(cè)試方法。
double可以理解為置換,它是所有模擬測(cè)試對(duì)象的統(tǒng)稱,我們也可以稱它為替身。一般來說,當(dāng)你創(chuàng)建任意一種測(cè)試置換對(duì)象時(shí),它將被用來替代某個(gè)指定類的對(duì)象。
stub可以理解為測(cè)試樁,它能實(shí)現(xiàn)當(dāng)特定的方法被調(diào)用時(shí),返回一個(gè)指定的模擬值。如果你的測(cè)試用例需要一個(gè)伴生對(duì)象來提供一些數(shù)據(jù),可以使用 stub 來取代數(shù)據(jù)源,在測(cè)試設(shè)置時(shí)可以指定返回每次一致的模擬數(shù)據(jù)。
spy可以理解為偵查,它負(fù)責(zé)匯報(bào)情況,持續(xù)追蹤什么方法被調(diào)用了,以及調(diào)用過程中傳遞了哪些參數(shù)。你能用它來實(shí)現(xiàn)測(cè)試斷言,比如一個(gè)特定的方法是否被調(diào)用或者是否使用正確的參數(shù)調(diào)用。當(dāng)你需要測(cè)試兩個(gè)對(duì)象間的某些協(xié)議或者關(guān)系時(shí)會(huì)非常有用。
mock與spy類似,但在使用上有些許不同。spy 追蹤所有的方法調(diào)用,并在事后讓你寫斷言,而 mock 通常需要你事先設(shè)定期望。你告訴它你期望發(fā)生什么,然后執(zhí)行測(cè)試代碼并驗(yàn)證最后的結(jié)果與事先定義的期望是否一致。
fake是一個(gè)具備完整功能實(shí)現(xiàn)和行為的對(duì)象,行為上來說它和這個(gè)類型的真實(shí)對(duì)象上一樣,但不同于它所模擬的類,它使測(cè)試變得更加容易。一個(gè)典型的例子是使用內(nèi)存中的數(shù)據(jù)庫來生成一個(gè)數(shù)據(jù)持久化對(duì)象,而不是去訪問一個(gè)真正的生產(chǎn)環(huán)境的數(shù)據(jù)庫。
對(duì)不同類型的模擬測(cè)試對(duì)象更多的細(xì)節(jié)討論參考:"Mocks Aren't Stubs"
Mock框架
模擬測(cè)試時(shí)的注意事項(xiàng):
-
依賴注入是你的好伙伴:使用依賴注入的話,你會(huì)發(fā)現(xiàn)使用 stub 和 mock 方式寫測(cè)試要容易的多; -
不要模擬你沒有的:應(yīng)該只為你代碼庫本身擁有的對(duì)象創(chuàng)建 mock 或 stub,而不是為第三方依賴或一些庫去創(chuàng)建。