摘要:而且,構(gòu)造函數(shù)不應(yīng)該包含行為,所以沒有值得測試的東西。一旦一個被創(chuàng)建了,你測試它的不為空因為你知道構(gòu)造函數(shù)創(chuàng)建了一個新的并將它賦給了變量?,F(xiàn)在為類的構(gòu)造函數(shù)編寫的測試出問題了,即便類運行良好,但并沒有包括。
在研究了有關(guān)測試的相關(guān)內(nèi)容,發(fā)現(xiàn)有些被忽略掉的很明顯的問題。
1、為什么需要測試從積極的方面來說,寫自動化測試的優(yōu)勢如下:
使重構(gòu)更簡單 —— 你可以自信的修改實現(xiàn)細(xì)節(jié),而不用去觸及公有 API。
避免代碼惡化—— 惡化在什么時候發(fā)生?在你修改代碼的時候。
提供了可執(zhí)行的說明和文檔 —— * 你在什么時候更想知道軟件實際上是如何工作的?在你想修改它們的時候
減少了創(chuàng)建軟件的時間 —— 怎么減少時間的?是通過更快速地修改你的代碼,出錯時測試會自信地告訴你哪里出錯了
降低了創(chuàng)建軟件的代價 —— 好吧,時間就是金錢,我的朋友
其實上述優(yōu)勢最大的就是,當(dāng)我們需要優(yōu)化代碼,進(jìn)行修改時,會給予我們一種保障。所以在自動化測試的支撐下,我們需要做的就比較簡單了。
2、測試的最佳實踐指導(dǎo)有 5 條被認(rèn)為是每個測試都應(yīng)該遵守的基本原則。便于記憶這 5 條規(guī)則的縮寫是: F.I.R.S.T.
測試應(yīng)該:
壞的實踐很快速(Fast) —— 測試應(yīng)該能夠被經(jīng)常執(zhí)行。
能隔離(Isolated) —— 測試本身不能依賴于外部因素或者其他測試的結(jié)果。
可重復(fù)(Repeatable) —— 每次運行測試都應(yīng)該產(chǎn)生相同的結(jié)果。
帶自檢(Self-verifying) —— 測試應(yīng)該包括斷言,不需要人為干預(yù)。
夠及時(Timely) —— 測試應(yīng)該和生產(chǎn)代碼一同書寫。
不要測試私有方法
私有方法意味著私有。如果你感到有必要測試一個私有方法,那么那個私有方法一定含有概念性錯誤,通常是作為私有方法,它做的太多了, 從而違背了單一職責(zé)原則
如果僅僅為了測試,就讓私有方法變?yōu)楣?,那么就會改變方法的私有性,會有被其他類調(diào)用的風(fēng)險。那么應(yīng)該該如何去做呢。
通過這個類的公有 API。永遠(yuǎn)通過公有 API 測試你的代碼。程序的公有 API 定義了一個約定,它是一組關(guān)于你的程序?qū)?yīng)于不同輸入時定義良好的一組期望。私有 API (私有方法或者整個類) 并沒有定義約定,并且可以不經(jīng)通知自行修改,所以你的測試 (或者你的同事) 不能依賴于它們。
通過這種方法測試你的私有方法,你可以自由地修改你的 (真正的) 私有代碼,并且通過劃分成只做一件事情,并經(jīng)過正確測試的小的類,來提升代碼的設(shè)計。
不要Stub 私有方法
Stub 私有方法和測試私有方法具有相同的危害,更重要的是,stub 私有方法將會使程序難以調(diào)試。
同樣,當(dāng)我們 stub 一個方法的時候,我們必須依據(jù)它做出的約定來進(jìn)行。但是私有方法沒有指定的約定的 —— 畢竟,這也是為什么它們是私有的原因。由于私有方法的行為可以不經(jīng)通知自行修改,你的 stub 可能與實際情況背道而馳,但是你的測試仍然會通過。這是多么的可怕啊,讓我們來看一個例子:
今天:一個類的公有方法依賴于該類的一個私有方法。這個私有方法 foo 永遠(yuǎn)不會返回空。為公有方法編寫的測試為了方便起見,我們 stub 出了私有方法。當(dāng) stub foo 方法的時候,你永遠(yuǎn)不會考慮到 foo 返回為空的情況,因為現(xiàn)在這種情況永遠(yuǎn)不會發(fā)生。
明天:這個私有方法被修改了,現(xiàn)在它返回空了。它是一個私有方法,所以這沒什么問題。為公有方法編寫的測試不會相應(yīng)地被修改 (“我正在修改一個私有方法,所以我為什么要更新我的測試?”)。公有方法現(xiàn)在在私有方法返回空的情況下會出錯,但是測試仍然會通過!
不要 Stub 外部庫
第三方代碼不應(yīng)該在你的測試中直接出現(xiàn)。
今天:你的網(wǎng)絡(luò)部分的代碼依賴于著名的 HTTP 庫 LSNetworking.為了避免使用實際的網(wǎng)絡(luò) (為了讓你的測試更快速更可信),你 stub 了那個庫中的方法 -[LSNetworking makeGETrequest:],沒有通過實際的網(wǎng)絡(luò)合適地替代了它的行為 (它通過一個封裝好的響應(yīng)調(diào)用了執(zhí)行成功的回調(diào))。
明天:你需要使用一個替代品來取代 LSNetworking (可能是 LSNetworking 已經(jīng)不再維護(hù)或者是你需要換成一個更先進(jìn)的庫,因為它有很多你需要的新特性等等)。這是一次重構(gòu),所以你不應(yīng)該修改測試。你替換了庫。你的測試會失敗,因為依賴的網(wǎng)絡(luò)沒有被 stub (-[LSNetworking makeGETrequest:]不會被調(diào)用)。
應(yīng)該做什么:測試中,依靠 stubbing 傘 (umbrella stubbing) 來替代那個庫的全部功能。
stubbing 傘 (一個我剛剛發(fā)明的術(shù)語) 包括了對于所有你的代碼可能用到的方式 -- 不管事現(xiàn)在還是將來 -- 的 stub。它們可以通過良好聲明的 API 完成一些任務(wù),而不去關(guān)心實現(xiàn)的細(xì)節(jié)。
不要測試構(gòu)造函數(shù)
構(gòu)造函數(shù)定義的是實現(xiàn)細(xì)節(jié),你不應(yīng)該測試構(gòu)造函數(shù),這是因為我們認(rèn)同測試應(yīng)該與實現(xiàn)細(xì)節(jié)解耦這一觀點。而且,構(gòu)造函數(shù)不應(yīng)該包含行為,所以沒有值得測試的東西。
今天:你有一個 Car 類,并包含一個構(gòu)造函數(shù)。一旦一個 Car 被創(chuàng)建了,你測試它的 Engine 不為空 (因為你知道構(gòu)造函數(shù)創(chuàng)建了一個新的 Engine 并將它賦給了變量 _engine)。
明天:Engine 類創(chuàng)建起來變得代價很高,所以你決定使用延遲初始化 (lazily initialize),在第一次調(diào)用 Engine 的 getter 方法時才初始化 Engine (這是很好的)。 現(xiàn)在為 Car 類的構(gòu)造函數(shù)編寫的測試出問題了,即便 Car 類運行良好,但 Car 并沒有包括 Engine。另一個可能是你的測試不會失敗,因為測試包含 Engine 的 Car 類會觸發(fā) Engine 的延遲加載。所以我的問題是:為什么還要測試?
3、如何進(jìn)行測試Given / When / Then模式
我們可以根據(jù) Given-When-Then 模式來組織我們的測試用例,將測試用例拆分成三個部分。
在 given 部分里,通過創(chuàng)建模型對象或?qū)⒈粶y試的系統(tǒng)設(shè)置到指定的狀態(tài),來設(shè)定測試環(huán)境。when 這部分包含了我們要測試的代碼。在大部分情況,這里只有一個方法調(diào)用。在 then 這部分中 ,我們需要檢查我們行為的結(jié)果:是否得到了我們期望的結(jié)果?對象是否有改變?這部分主要包括一些斷言。簡單一點來講就是,設(shè)定環(huán)境、調(diào)用方法、檢測結(jié)果。
簡單的例子看起來是這個樣子的:
- (void)testThatItDoesURLEncoding { // given NSString *searchQuery = @"$content$amp;?@"; HTTPRequest *request = [HTTPRequest requestWithURL:@"/search?q=%@", searchQuery]; // when NSString *encodedURL = request.URL; // then XCTAssertEqualObjects(encodedURL, @"/search?q=%24%26%3F%40"); }
這種簡單的模式使我們能夠更容易地書寫和理解這些測試用例,因為它們都遵循了同樣的模式。為了更快地瀏覽,我們甚至?xí)诿總€部分的代碼上寫上 “given”,“when”,“then” 的注釋。通過這種方式,這個方法就能很快被理解。
Mock
在iOS測試中的mock測試框架可以采用OCMock。
我們用 mock 來管理一個對象的所有依賴項。通過這個方式,我們可以測試這個類在隔離情況下的行為。但是這里有個明顯的缺點,那就是當(dāng)我們修改了一個類后,其他依賴于這個類的類的單元測試不能自動失敗。但是關(guān)于這一點我們可以通過集成測試來補救,因為它可以測試所有的類。
我們不應(yīng)該‘過度mock’,也就是說,去 mock 除了被測試的對象的其他對象這樣的習(xí)慣是要盡量避免的。當(dāng)我們剛開始的時候,我們經(jīng)常會這樣做,我們甚至?xí)?mock 那些簡單到可以作為方法參數(shù)的對象?,F(xiàn)在我們使用了不少真實的對象,而不是 mock 它們。
4、編寫測試是一種投資我們需要花時間編寫和維護(hù)它們。我們可以證明這種投資有回報的唯一方法就是我們期望節(jié)省時間。將實現(xiàn)細(xì)節(jié)和測試耦合在一起會減少測試帶來的回報,使得那些投資變得不合算,甚至在某些情況下變得一文不值。
在編寫測試、重構(gòu)以及修改系統(tǒng)行為的時候,檢查你的測試在面對錯誤的原因時是失敗還是通過,然后退一步問問自己,那些測試是否能夠最大化你投資的成果
測試代碼量會比被測試代碼還要多
目前為止,我們的編碼庫已經(jīng)縱橫 190 個文件和 18,000 行代碼,達(dá)到了 544 kB。我們測試部分的代碼現(xiàn)在差不多有1,200 kB,大概有被測試代碼的兩倍。雖然我們還沒有完全結(jié)束這個項目,但是已經(jīng)接近尾聲。
引用文章
Real-World Testing with XCTest
Bad Testing Practices
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/8749.html
摘要:正是因為這樣的協(xié)議存在一些自動化測試框架可以使用多種語言編寫測試腳本。支持了所有的主流瀏覽器,同時還支持了和的移動應(yīng)用測試。接下來就帶著大家一步一步使用進(jìn)行進(jìn)行自動化測試全局安裝的如果覺得比較慢,就換淘寶的鏡像吧。 Macaca macaca是阿里開源的基于Node.js開發(fā)的自動化測試工具,支持native,hybird,moblie web,關(guān)于macaca具體的內(nèi)容參見官網(wǎng)mac...
摘要:,部分設(shè)備支持功能,在啟用功能后,系統(tǒng)會對內(nèi)存進(jìn)行壓縮,增加,會相應(yīng)減少,由于壓縮會占用資源,同時相應(yīng)會導(dǎo)致降低虛擬內(nèi)存整機可用剩余內(nèi)存,極限測試情況下開啟可能會造成性能損耗。 一、PerfDog簡介 PerfDog性能狗是移動全平臺iOS/Android性能測試工具,快速定位分析性能問題,...
摘要:本文目的是通過自己寫的一個的簡單的庫花密密碼生成工具,來學(xué)習(xí)我認(rèn)為的庫開發(fā)的一些規(guī)范,以及上持續(xù)構(gòu)建你的項目的一些方法。給自己的項目開啟持續(xù)構(gòu)建。包發(fā)布以及當(dāng)你的代碼完成后,測試完成后。 本文目的是通過自己寫的一個php的簡單的庫(花密密碼生成工具), 來學(xué)習(xí)我認(rèn)為的php庫開發(fā)的一些規(guī)范,以及github上持續(xù)構(gòu)建你的項目的一些方法。其實是為了顯示下邊一系列的的徽章 showImg(...
摘要:王者榮耀項目組高級測試工程師工程師文化團隊中的實踐本文不是一篇入門教程,而是從結(jié)合實際場景,闡述在團隊協(xié)作中如何去好好地應(yīng)用。 CI Weekly 圍繞『 軟件工程效率提升』 進(jìn)行一系列技術(shù)內(nèi)容分享,包括國內(nèi)外持續(xù)集成、持續(xù)交付,持續(xù)部署、自動化測試、 DevOps 等實踐教程、工具與資源,以及一些工程師文化相關(guān)的程序員 Tips 。同步于 flow.ci Blog、微信公眾號、官方微...
閱讀 1599·2023-04-26 02:29
閱讀 3134·2021-10-11 10:58
閱讀 2925·2021-10-08 10:16
閱讀 3185·2021-09-24 09:47
閱讀 1593·2019-08-29 16:56
閱讀 2745·2019-08-29 11:03
閱讀 2030·2019-08-26 13:35
閱讀 3199·2019-08-26 13:34