實踐1:每個功能類都應提供單元測試,且每一個測試類,只依賴于其要測試的受測類。使用偽造對象可以避免對其他類的依賴。
解釋:保證一個測試類只關注一個被測類,當測試不通過時,就能迅速的定位到是誰發生了錯誤,而不會受到其他類的干擾。
簡單的數據類等可以不提供,但是要保證該測試的都要覆蓋到。并不存在一種合適的度量指標可以量化地判斷某種單元測試方案是否成功。常用的標準(代碼覆蓋率和成功執行的測試用例數)都可以在受測軟件的質量不變的情況下人為的修改(作假)。當然,在無法確保程序員素質的情況下,作為沒有辦法的辦法,使用這種標準也是可以的(或者無奈的說,必須的)。單元測試需要程序員自己把關,關注哪些功能確實需要測試覆蓋。這也就是前面所說的一些程序員不相信單元測試可以提高生產率的理由--它更多的依賴于程序員的素質,這是沒有保證的。但同樣的,由于敏捷是一種以人為本的思想實踐,因而這種行為似乎又是一種必然。
實踐1.1:使用偽造類避免對其他類的依賴。
解釋:避免依賴的一種手段。
例如,某個被測的方法聲明是這樣的:
-(void)xxxx:(Person *)person;
如果測試時傳入Person的話,就造成了測試類依賴于兩個類。當由于person中的錯誤引發測試不通過時,就不能迅速的定位到受測類中是否有問題。遇到這種情況,就可以使用偽造類。假如方法中只使用了person的一個屬性name,那么可以將方法名重構為
-(void)xxxx:(id)person;(此處id有待商榷,只是這樣做最簡單)
然后在單元測試的target中添加只包含name屬性的fakePerson來作為偽造類。這樣,一旦發生錯誤就可以迅速的推測出錯誤的來源。
實踐1.2:使用偽造環境避免其他環境的干擾。
解釋:適合于異步的方法測試。
很經常遇到的一種情況是測試有網絡環境的代碼。由于異步的存在,這會造成測試代碼不好寫。一種簡單的解決方法是,我們假定網絡一定是通暢的,則我們測試的代碼將分為兩部分,即拼裝發送功能和接收解析功能。假如發送和接收功能各自都能通過測試,那么我們大約可以確定這個異步方法的正確性。另一種方法是使用GHUnit,它支持異步代碼的測試。
實踐2:測試用例(方法)名應該是自解釋的且是獨立的。
解釋:基本功。
如果被測試類的名稱是XXX,那么測試類可以命名為XXXTests。而對于其中要測試的功能,命名應該是自解釋的。這可以在發現錯誤時盡快的定位問題所在。例如,如果某個屬性obj應該是非空的,那么我們可以將其命名為:
-(void)testObjNotNil{}
每個方法目標應該是單一的,大多數情況下每個方法內都只有一個斷言語句;方法不應該依賴于其他方法的結果作為輸入,保證原子性。
實踐3:斷言語句需要解釋測試者的意圖。
解釋:基本功
每種單元測試框架都提供了很多斷言語句,從根本上來說它們都是一樣的。但是測試者需要根據自己的目的選擇適當的語句,這樣才可以讓別人閱讀測試代碼時理解用例設計的目的。例如對于STAssertNil和STAssertNotNil等等。
實踐4:判斷某個意圖有沒有達到的很好的方法是檢測方法影響的數據有沒有合理的變化。
解釋:基本功
由于單元測試是使用斷言語句來做判斷的,因而最容易做的就是判斷數據的變化。這也就限定了單元測試能測試的方法范圍,即引起數據變化的方法。對于一些純展示的方法,例如播放一段特效,這種方法是無法靠單元測試來進行約束的。測試數據的特性包括取值范圍(int、float等),排列順序(NSArray等),類型等等。
實踐5:運用重構的手段使方法變得易于被測試。
解釋:單元測試是保障重構安全的手段,重構也可以使代碼易于被測試。
什么樣的代碼是容易進行單元測試的?最簡單的一點就是,每個被測方法都應該是功能單一的。當然,這也是代碼規范中應該做到的。方法的功能單一,則測試方法的斷言也會比較好確定。如果你發現某個方法很難進行測試,則就應該對這個方法進行拆分重構。
實踐5.1:面向抽象設計類之間的關系。
解釋:利于偽造類的實現。
類之間通訊如果依賴于抽象(接口),則可以較容易的使用偽造類。參照實踐1.1。
原文轉自:http://www.uml.org.cn/Test/201306072.asp