BDD旨在解決具體問(wèn)題粱玲,幫助開(kāi)發(fā)人員確定應(yīng)該測(cè)試些什么墙歪。它提供了一個(gè)DSL
( Domain-specific language乌企,域特定語(yǔ)言)鼓勵(lì)開(kāi)發(fā)者弄清楚他們的需求晌该,并且它引入了一個(gè)通用語(yǔ)言幫助你輕易理解測(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缺少匹配,也沒(méi)有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ǔ)起來(lái),以便在后續(xù)過(guò)程中使用虚循;
注意:盡管 Objective-C 本身沒(méi)有所謂的構(gòu)造器而是使用初始化方法同欠,但因?yàn)闃?gòu)造器注入是 DI 的標(biāo)準(zhǔn)概念,放到各種語(yǔ)言中也是普遍適用的横缔,所以還是準(zhǔn)備用構(gòu)造器注入這個(gè)詞來(lái)代指初始化注入铺遂。
-
屬性注入
:采用屬性賦值方式,以便在后續(xù)過(guò)程中使用剪廉; -
方法注入
:如果依賴對(duì)象只在某一個(gè)方法中被使用娃循,則可以利用方法參數(shù)做注入; -
環(huán)境上下文
:當(dāng)通過(guò)一個(gè)類方法 (例如單例) 來(lái)訪問(wèn)依賴對(duì)象時(shí)斗蒋,在單元測(cè)試中可以通過(guò)兩種方式來(lái)控制依賴對(duì)象捌斧。- 如果可以控制單例本身,則可以通過(guò)公開(kāi)其屬性來(lái)控制其狀態(tài)泉沾;
- 如果上述方式無(wú)效或者所操作的單例不歸自己管理捞蚂,此時(shí)就該運(yùn)用swizzling了:直接替換類方法,讓其返回你所期望的返回值跷究。
寫測(cè)試
測(cè)試用例使我們的代碼質(zhì)量變得可靠姓迅,同時(shí)讓我們能夠放心地重構(gòu)或者修改代碼,并保證我們的修改沒(méi)有破壞其他部分俊马。
原文:糟糕的測(cè)試
可以根據(jù)Given-When-Then模式來(lái)組織我們的測(cè)試用例丁存。
寫測(cè)試的時(shí)候問(wèn)自己兩個(gè)問(wèn)題:
- “如果我修改了我的生產(chǎn)代碼,測(cè)試是會(huì)失敗 (還是通過(guò)) 呢?”
- “那是一個(gè)讓測(cè)試失敗 (或者通過(guò)) 的好的理由么?”
測(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)是降低未來(lái)的變化所帶來(lái)的成本界睁,不要將測(cè)試和實(shí)現(xiàn)細(xì)節(jié)耦合在一起觉增。
-
不要測(cè)試私有方法
:可以進(jìn)行置換測(cè)試 -
不要 Stub 私有方法
:stub 私有方法將會(huì)使程序難以調(diào)試 -
不要 Stub 外部庫(kù)
:第三方代碼不應(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í)際代碼來(lái)編寫一些測(cè)試用例
原文:置換測(cè)試: Mock, Stub 和其他
mock測(cè)試就是在測(cè)試過(guò)程中,對(duì)于某些不容易構(gòu)造或者不容易獲取的對(duì)象访惜,用一個(gè)虛擬的對(duì)象來(lái)創(chuàng)建以便測(cè)試的測(cè)試方法敞斋。
double可以理解為置換,它是所有模擬測(cè)試對(duì)象的統(tǒng)稱疾牲,我們也可以稱它為替身植捎。一般來(lái)說(shuō),當(dāng)你創(chuàng)建任意一種測(cè)試置換對(duì)象時(shí)阳柔,它將被用來(lái)替代某個(gè)指定類的對(duì)象焰枢。
stub可以理解為測(cè)試樁,它能實(shí)現(xiàn)當(dāng)特定的方法被調(diào)用時(shí)舌剂,返回一個(gè)指定的模擬值济锄。如果你的測(cè)試用例需要一個(gè)伴生對(duì)象來(lái)提供一些數(shù)據(jù),可以使用 stub 來(lái)取代數(shù)據(jù)源霍转,在測(cè)試設(shè)置時(shí)可以指定返回每次一致的模擬數(shù)據(jù)荐绝。
spy可以理解為偵查,它負(fù)責(zé)匯報(bào)情況,持續(xù)追蹤什么方法被調(diào)用了嘀韧,以及調(diào)用過(guò)程中傳遞了哪些參數(shù)氨菇。你能用它來(lái)實(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ì)象,行為上來(lái)說(shuō)它和這個(gè)類型的真實(shí)對(duì)象上一樣叙身,但不同于它所模擬的類渔扎,它使測(cè)試變得更加容易。一個(gè)典型的例子是使用內(nèi)存中的數(shù)據(jù)庫(kù)來(lái)生成一個(gè)數(shù)據(jù)持久化對(duì)象曲梗,而不是去訪問(wèn)一個(gè)真正的生產(chǎn)環(huán)境的數(shù)據(jù)庫(kù)赞警。
對(duì)不同類型的模擬測(cè)試對(duì)象更多的細(xì)節(jié)討論參考:"Mocks Aren't Stubs"
Mock框架
模擬測(cè)試時(shí)的注意事項(xiàng):
-
依賴注入是你的好伙伴
:使用依賴注入的話,你會(huì)發(fā)現(xiàn)使用 stub 和 mock 方式寫測(cè)試要容易的多虏两; -
不要模擬你沒(méi)有的
:應(yīng)該只為你代碼庫(kù)本身?yè)碛械膶?duì)象創(chuàng)建 mock 或 stub愧旦,而不是為第三方依賴或一些庫(kù)去創(chuàng)建。