天天看點

Kiwi,BDD行為測試架構--iOS攻城獅進階必備技能

kiwi 是一個适用于ios開發的行為驅動測試架構,旨在提供一個足夠簡單易用的bdd庫.

把 amazingapptests 改為你自己的工程中的tests target的名字,比如我的是 ios122tests,然後更新即可:

為了快速測試kiwi是否安裝成功,你可以用下面的代碼替換到你的 tests目錄下已有的檔案中的預設内容,然後點選xcode導航欄 product->test(或者使用快捷鍵 cmd + u),此時如果提示你 test failed,點選錯誤提示,會在左側第四導航欄看到類似下面的錯誤:

如果不能看到上述錯誤資訊,說明你的工程配置可能有問題,可以參考這裡詳細微調下: getting started with kiwi 2.0

期望,用來驗證用例中的對象行為是否符合你的語氣.一個期望,具有如下形式: [[subject should] somecondition:anargument].此處 [subject should]是表達式的類型, ... somecondition:anargument] 是比對器的表達式.

示例:

[subject should] 和 [subject shouldnot] 表達式,類似于一個接收器,用于接收一個期望比對器.他們後面緊跟的是真實的比對表達式,這些表達式将真正被用于計算.

預設地,主語守衛(一種機制,可以保證nil不引起崩潰)也會在[subject should ]和 [subject shouldnot]被使用時建立.給 nil 發送消息,通常不會有任何副作用.但是,你幾乎不會希望:一個表達式,隻是為了給某個對象傳遞一個無足輕重的消息,就因為對象本身是nil.也就說,向nil對象本身發送消息,并不會有任何副作用;但是在bbd裡,某個要被傳遞消息的對象是nil,通常是非預期行為.是以,這些表達式的對象守衛機制,會将左側無法判定為不為nil的表達式判定為 fail失敗.

"裝箱"是固定術語譯法,其實即使我們ios常說的基本類型轉nsobject類型(事實如此,勿噴).

部分表達式中,比對器表達式的參數總是nsobject對象.當将一個标量(如int整型,float浮點型等)用于需要id類型參數的地方時,應使用thevalue(一個标量)宏将标量裝箱.這種機制也适用于: 當一個标量需要是一個表達式的主語(主謂賓,基本文法規則,請自行腦補)時,或者一個 存根 的值需要是一個标量時.

消息模式

在ios中,常将調用某個執行個體對象的方法成為給這個對象發送了某個消息.是以"消息模式"中的"消息",更多的指的的執行個體對象的方法;"消息模式"也就被用來判斷對象的某個方法是否會調用以及是否會按照預期的方式調用.

一些 kiwi 比對器支援使用消息模式的期望.消息模式部分,常被放在一個表達式的後部,就像一個将要發給主語的消息一樣.

期望:數值 和 數字

期望: 子串比對

期望: 正規表達式比對

期望: 數量的變化

期望: 對象測試

期望: 集合

對于集合主語(即,主語是集合類型的):

對于集合鍵(即此屬性/方法名對應/傳回一個集合類型的對象):

如果主語是一個集合(比如 nsarray數組), coollectionkey 可以是任何東西(比如 items),隻要遵循文法結構就行.否則, coollectionkey應當是一個可以發送給主語并傳回集合類型資料的消息.

更進一步說: 對于集合類型的主語,coollectionkey的數量總是根據主語的集合内的元素數量, coollectionkey 本身并無實際意義.

期望: 互動和消息

這些期望用于驗證主語是否在從建立期望到用例結束的這段時間裡接收到了某個消息(或者說對象的某個方法是否被調用).這個期望會同時存儲 選擇器或參數等資訊,并依次來決定期望是否滿足.

這些期望可用于真實或模拟的獨享,但是在設定 receive 表達式時,xcode 可能會給警告(報黃).

對參數無要求的選擇器:

含有指定參數的選擇器:

注意你可以将 any()通配符用作參數.如果你隻關心一個方法的部分參數的值,這回很有用:

期望:通知

example:

期望: 異步調用

期望: 異常

自定義比對器

kiwi中,自定義比對器的最簡單方式是建立kwmatcher的子類,并以适當的方式重寫下面示例中的方法.

為了讓你自定義的比對器在規則中可用,你需要在規則中使用 registermatchers(namespaceprefix)進行注冊.

看下kiwi源檔案中的比對器寫法(如kwequalmatcher等),将會使你受益匪淺.

模拟對象模拟某個類,或者遵循某個寫一個.他們讓你在完全功能完全實作之前,就能更好地專注于對象間的互動行為,并且能降低對象間的依賴--模拟或比避免那些運作規則時幾乎很難出現的情況.

模拟 null 對象

通常模拟對象收到一個非預期的選擇器或消息模式時,會抛出異常(ps:ios開發常見錯誤奔潰之一).在模拟對象上使用 stub 或 receive期望,期望的消息會自動添加到模拟對象上,以實作對方法的模拟.

如果你不關心模拟對象如何處理其他非預期的消息,也不想在收到非預期消息時抛出異常,那就使用 null 模拟對象吧(也即 null 對象).

模拟類的執行個體

建立類的模拟執行個體(nsobject 擴充):

建立類的模拟執行個體:

模拟協定的執行個體

建立遵循某協定的執行個體:

存根,能傳回指定定選擇器或消息模式的封裝好的請求.kiwi中,你可以存根真實對象(包括類對象)或模拟對象的方法.沒有指定傳回值的存根,将會對應傳回nil,0等零值.存根需要傳回标量的,标量需要使用 thevalue(某個标量)宏 裝箱.

所有的存根都會在規範的一個例子的末尾(一個itblock)被清除.

存根選擇器:

存根消息模式:

捕捉參數

有時,你可能想要捕捉傳遞給模拟對象的參數.比如,參數可能沒有是一個沒有很好實作 isequal: 的對象,如果你想确認傳入的參數是否是需要的,那就要單獨根據某種自定義規則去驗證.另外一種情況,也是最長遇到的情況,就是模拟對象接收的消息的某個參數是一個block;通常必須捕捉并執行這個block才能确認這個block的行為.

存根的記憶體管理問題

未來的某天,你或許需要存根alloc等法官法.這可能不是一個好主意,但是如果你堅持,kiwi也是支援的.需要提前指出的是,這麼做需要深入思考某些細節問題,比如如何管理初始化.

kiwi 存根遵循 objective-c 的記憶體管理機制.當存根将傳回值寫入一個對象時,如果選擇器是以alloc,或new開頭,或含有 copy時,retain消息将會由存根自動在對象發送前發送.

是以,調用者不需要特别處理由存根傳回的對象的記憶體管理問題.

警告

kiwi深度依賴objective-c的運作時機制,包括消息轉發(比如 forwardinvocation:).因為kiwi需要預先判斷出來哪些方法可以安全調用.使用kiwi時,有一些慣例,也是你需要遵守的.

為了使情況簡化和有條理,某些方法/選擇器,是決不能在消息模式中使用,接收期望,或者被存根;否則它們的正常行為将會被改變.不支援使用這些控制器,而且使用後的代碼的行為結果也會變的很奇怪.

在實踐中,對于高品質的程式代碼,你可能不需要擔心這些,但是最好還是對這些有些印象.

黑名單(使用有風險):

白名單(可安全使用):

ios應用經常有元件需要在背景和主線程中内容溝通.為此,kiwi支援異步測試;是以就可以進行內建測試-一起測試多個對象.

expectfuturevalue() 和 shouldeventually

為了設定異步測試,你 必須 使用 expectfuturevalue 裝箱,并且使用 shouldeventually 或 shouldeventuallybeforetimingoutafter來驗證.

shouldeventually 預設在判定為失敗前等待一秒.

标量的處理

當主語中含有标量時,應該使用 expectfuturevalue中使用 thevalue裝箱标量.例如:

shouldeventuallybeforetimingoutafter()

這個block預設值是2秒而不是1秒.

反轉

也有shouldnoteventually和 shouldnoteventuallybeforetimingoutafter 的變體.

一個基于lrresty的示例:

這個block會在比對器滿足或者逾時(預設: 1秒)時完成.

this will block until the matcher is satisfied or it times out (default: 1s)

繼續閱讀