Xcode測試
前言
????總算在今天把單元測試的官方文檔翻譯寫成了一片博客。首先感謝黨,感謝人民,感謝我的父母。也必須感謝下我們部門的領(lǐng)導(dǎo)給了我一個(gè)這樣的時(shí)間來做這件事情。翻譯的不算太好,很多地方都還只是一個(gè)概念,在翻譯的時(shí)候存在一些困難。而且單元測試也不止于翻譯了這篇官方的文檔,它應(yīng)該是一系列的文檔和說明。我會(huì)在今年的時(shí)間里,努力去寫出來一個(gè)雛形。希望更多的人可以通過這些介紹認(rèn)識(shí)到測試。
介紹
使用Xcode測試
Xcode提供的一個(gè)功能,可以進(jìn)行廣泛的軟件測試。主要測試你的項(xiàng)目的健壯性,減少BUG,讓你的產(chǎn)品更快的分發(fā)和銷售。按照預(yù)期的功能測試,提高用戶的滿意度。測試可以幫助你更快開發(fā)、少做無用功。

目錄結(jié)構(gòu)
在這份文件中,你將學(xué)習(xí)如何使用Xcode包含的測試功能。XCTest框架添加測試的時(shí)候自動(dòng)鏈接上去的。
- 1.快速啟動(dòng),在Xcode5引進(jìn)XCTest框架開始,配置項(xiàng)目測試的過程已經(jīng)簡化可以在導(dǎo)航欄自動(dòng)的測試和運(yùn)行。
- 2.性能測試,Xcode6以及更高的版本讓你能夠跟蹤和衡量基本單位的性能變化。
- 3.UI測試,Xcode7增加了對用戶界面的測試能力。
- 4.持續(xù)集成和Xcode服務(wù)器,Xcode測試可以使用命令腳本來執(zhí)行或配置在Mac上的漫游器自動(dòng)運(yùn)行Xcode服務(wù)器上執(zhí)行。
- 5.現(xiàn)代化,Xcode中包含轉(zhuǎn)換一測試的OCUnit測試項(xiàng)目遷移。
前提
你應(yīng)該熟悉應(yīng)用程序的設(shè)計(jì)和編程的概念。
快速啟動(dòng)
快速啟動(dòng)其實(shí)就是介紹了測試的組成部分你可以對測試有一個(gè)簡單的理解。
介紹測試的導(dǎo)航欄
當(dāng)你準(zhǔn)備做測試工作的時(shí)候,你會(huì)經(jīng)常使用測試的導(dǎo)航欄。
測試的導(dǎo)航欄目的是緩解你測試代碼的編寫、管理、運(yùn)行、審查測試的操作。你可以點(diǎn)擊導(dǎo)航欄中的圖標(biāo),位于show the issue導(dǎo)航和show the debug導(dǎo)航之間。當(dāng)你創(chuàng)建了一些測試的項(xiàng)目你可以在這里看到一個(gè)導(dǎo)航視圖。

圖中的測試導(dǎo)航現(xiàn)實(shí)測試包、類和包含在測試項(xiàng)目方法的分層列表。圖中的項(xiàng)目是一個(gè)簡單的計(jì)算器項(xiàng)目。計(jì)算器使用一個(gè)框架實(shí)現(xiàn),你可以在最高層的SampleCalcTests測試包里看到測試的代碼。
注意:Xcode的測試目標(biāo)產(chǎn)生后顯示在測試導(dǎo)航里。如果你的測試使用數(shù)據(jù)文件、圖像等等,他們可以被添加到所述的測試包,并且可以在運(yùn)行的時(shí)候訪問一個(gè)NSBundle的API。使用+[NSBundle bundleForClass:]確定你獲得正確的包來進(jìn)行測試。Xcode的方案控制構(gòu)建了什么。方案還控制哪個(gè)可用的測試方法用于測試操作需要去執(zhí)行。你可以啟用和控制通過點(diǎn)擊該項(xiàng)目在測試導(dǎo)航的列表中,選擇啟用或者從快捷菜單中禁用。從而啟用或禁用測試包、類和方法。
此視圖中的主要測試包是SampleCalcTests。SampleCalcTests包括一個(gè)測試類,后面包含九個(gè)測試方法。運(yùn)行按鈕在測試項(xiàng)目名稱的右側(cè)。這是一個(gè)非常方便的方法,所有的測試項(xiàng)目都集中到了這里(如果使用了一些第三方的測試可能有一些不會(huì)出現(xiàn)在這里列表當(dāng)中)。運(yùn)行以后紅色的X代表測試不通過,綠色的對勾代表測試通過。運(yùn)行的測試項(xiàng)目是使用斷言來檢測通過或者故障。

單擊列表中的任何測試類或者測試方法打開測試類。測試類和測試方法在gutter都會(huì)顯示一個(gè)可點(diǎn)擊的測試的標(biāo)志(可進(jìn)行單獨(dú)的測試)。
在測試導(dǎo)航的底部你可以添加一個(gè)測試,也可以通過一些字符串縮小你的查找范圍。
為你的App添加測試
在Xcode5或者更高的版本你創(chuàng)建應(yīng)用的時(shí)候可以通過勾選測試的按鈕來為項(xiàng)目添加一個(gè)測試。當(dāng)你創(chuàng)建好以后你可以在你的項(xiàng)目里看到一個(gè)測試包、測試和模版測試的方法。但是你的項(xiàng)目可能是由比較早的Xcode版本生成的。這里介紹的就是當(dāng)你項(xiàng)目里預(yù)先沒有測試的時(shí)候的一些操作。
創(chuàng)建一個(gè)測試Target
打開測試導(dǎo)航,單擊左下角的加號(hào)按鈕,new unit test target。

在彈出框中選擇OS X或者iOS單元測試,然后單擊下一步,設(shè)置相關(guān)的信息。

點(diǎn)擊finish,完成以后點(diǎn)開。包含一個(gè)模版測試類和兩個(gè)測試方法的模版。

運(yùn)行測試,查看結(jié)果
現(xiàn)在你為你的項(xiàng)目添加了一個(gè)測試,然后去開發(fā)測試一些有意義的東西。首先按住鼠標(biāo)指針移動(dòng)到SampleCalcTests在測試導(dǎo)航測試類,然后點(diǎn)擊運(yùn)行按鈕運(yùn)行該類中的所有測試方法。結(jié)果在方法名稱的右邊,編輯區(qū)方法名的左邊。

因?yàn)槟K測試和性能測試都是空的,所以測試成功了。并沒有失敗的斷言。measureBlock:處單擊左側(cè)的“鉆石”會(huì)顯示性能測試的結(jié)果。

這個(gè)面板允許設(shè)置性能基線以及編輯基線和最大STDDREV參數(shù)。
編輯測試和重新運(yùn)行
這個(gè)實(shí)例項(xiàng)目是一個(gè)計(jì)算器應(yīng)用程序,你需要檢查加、減、乘、除算法的正確性,以及測試其他計(jì)算器功能的操作。測試是在項(xiàng)目中添加和編寫的,你可以測試任何你想要的測試。(這就要求你有一個(gè)很好的代碼結(jié)構(gòu)來提供測試)
eg:你可以在SampleCalcTests.m中添加實(shí)例聲明和引入類。
<pre><code>
import <XCTest/XCTest.h>
//
// Import the application specific header files
import "CalcViewController.h"
import "CalcAppDelegate.h"
@interface CalcTests : XCTestCase {
// add instance variables to the CalcTests class
@private
- NSApplication *app;
- CalcAppDelegate *appDelegate;
- CalcViewController *calcViewController;
- NSView *calcView;
}
*@end
</code></pre>
然后給測試方法的起一個(gè)描述性的名稱,如testAddition并添加要實(shí)施的方法。
<pre><code>
*- (void) testAddition
*{
*//obtain the app variables for test access
*App = [NSApplication sharedApplication];
calcViewController = (CalcViewController)[[NSApplicationsharedApplication] delegate];
*calcView = calcViewController.view;
*//perform two addition tests
*[calcViewController press:[calcView viewWithTag: 6]]; // 6
*[calcViewController press:[calcView viewWithTag:13]]; // +
*[calcViewController press:[calcView viewWithTag: 2]]; // 2
*[calcViewController press:[calcView viewWithTag:12]]; // =
*XCTAssertEqualObjects([calcViewController.displayField stringValue],@"8", @"Part 1 failed.");
*[calcViewController press:[calcView viewWithTag:13]]; // +
*[calcViewController press:[calcView viewWithTag: 2]]; // 2
*[calcViewController press:[calcView viewWithTag:12]]; // =
*XCTAssertEqualObjects([calcViewController.displayField stringValue],@"10", @"Part 2 failed.");
}
</code></pre>
如果你改變了測試的方法,測試導(dǎo)航列表也會(huì)做相應(yīng)的改變。

編輯完以后可以使用測試導(dǎo)航(或者gutter)來運(yùn)行testAddition方法。

當(dāng)一個(gè)斷言失敗,在測試導(dǎo)航和gutter會(huì)突出顯示。根據(jù)提示信息你可以非常輕易的找到這個(gè)錯(cuò)誤。進(jìn)行修改之后就能夠運(yùn)行成功。

使用setUp()和tearDown()方法
Xcode運(yùn)行一個(gè)測試包的時(shí)候會(huì)走這個(gè)測試類中的所有方法。那這個(gè)測試類中如果都需要一個(gè)初始化對象,你就要在每一個(gè)方法中對這個(gè)對象進(jìn)行初始化,這樣就會(huì)造成很多重復(fù)的代碼。但是XCTest框架提供了兩個(gè)實(shí)例方法用于測試類的初始化和釋放。你可以用這兩個(gè)實(shí)例方法將這些共同調(diào)用的方法寫進(jìn)去。
使用setup和teardown方法非常簡單。
<code><pre>
*- (void)setup
{
- [super setUp];
- *// Put setup code here. This method iscalled before the invocation of each test method in the class.
- *// obtain the app variables for test access
- *app = [NSApplication sharedApplication];
- calcViewController = (CalcViewController)[[NSApplicationsharedApplication] delegate];
- *calcView = calcViewController.view;
}
</code></pre>
Setup方法會(huì)在測試方法之前調(diào)用,所以測試方法可以直接試用初始化過的屬性。

概要
從這個(gè)簡短的快速入門可以看出來,為一個(gè)項(xiàng)目添加測試是很簡單的。但是還是有一些注意事項(xiàng):
- Xcode中設(shè)置了大部分的基本測試配置。當(dāng)你添加一個(gè)新的測試的時(shí)候,Xcode會(huì)自動(dòng)為你添加這些測試方法。使用一個(gè)單獨(dú)的方法進(jìn)行測試,可以在測試導(dǎo)航中找到。
- 測試導(dǎo)航可以讓你輕松的找到編輯測試的方法,你可以運(yùn)行,在導(dǎo)航測試或者gutter。測試失敗的時(shí)候你可以在gutter中看到失敗的標(biāo)志。
- 單個(gè)測試方法可以包括多個(gè)斷言,從而導(dǎo)致單一的合格或者不合格的測試結(jié)果。你可以根據(jù)需求來做簡單或者復(fù)雜的測試。setup和teardown實(shí)例方法可以讓你將通用的代碼寫在里邊。
基礎(chǔ)測試
測試是指檢驗(yàn)?zāi)愕膽?yīng)用程序代碼和庫代碼能否成功運(yùn)行的過程,用于衡量預(yù)期結(jié)果。通過執(zhí)行一些操作,測試可在執(zhí)行一些操作后檢查一個(gè)對象的實(shí)例變量的狀態(tài),以確定你的代碼在受到邊界條件變化時(shí)是否會(huì)拋出一個(gè)特定的異常等。
定義測試范圍
所有的軟件都是通過很多的單元組合起來的,也就是說,小的組件合在一起形成較大的、功能更強(qiáng)的高級組件,直到符合項(xiàng)目的需求。良好的測試需要涵蓋該組合的所有功能。其中單元測試通常處理該項(xiàng)目功能級的小組件。而XCTest允許你為任何層次結(jié)構(gòu)的各個(gè)級別的組件編寫相應(yīng)的測試。
測試組件由什么構(gòu)成完全取決于你自己,可以是一個(gè)類中的一個(gè)方法,也可以是完成一個(gè)基本目的的一組方法。例如,一個(gè)算術(shù)運(yùn)算,參見蘋果的官方demo。處理tableView的內(nèi)容間和代碼數(shù)據(jù)結(jié)構(gòu)中持有列表名稱間的交互有不同的方法。每個(gè)方法的操作都意味著應(yīng)用程序功能的組成部分對它的測試。一個(gè)測試組件的行為應(yīng)該是完全確定的,無論測試成功或者失敗。
把你的應(yīng)用程序的行為劃分為越多的組件,就越能有效的測試你的代碼能否滿足參考標(biāo)準(zhǔn)的各種細(xì)節(jié),尤其是當(dāng)項(xiàng)目不斷的迭代更新的時(shí)候。對于很多組件組成的大型項(xiàng)目來說,你需要運(yùn)行很多的測試來徹底檢測整個(gè)項(xiàng)目。如果可能的話,測試應(yīng)該快速運(yùn)行,擔(dān)憂一些測試確實(shí)很大,所以運(yùn)行可能會(huì)慢一點(diǎn)。當(dāng)有一些故障出現(xiàn)的時(shí)候,可以運(yùn)行一些小的測試快速測試,這樣可以輕松診斷和修復(fù)問題。
為項(xiàng)目組件設(shè)計(jì)測試是測試驅(qū)動(dòng)開發(fā)(test-driven-development TDD)的基礎(chǔ),也是一種編寫代碼測試之前編寫測試邏輯的編碼方式。這種開發(fā)方法可以讓你在實(shí)施之前確定代碼需求和邊界情況。編寫測試后,開發(fā)旨在通過測試的算法。在代碼通過測試以后,你才有了提高代碼的基礎(chǔ),才有信心在下一次運(yùn)行這些測試時(shí)能鑒定一些預(yù)期行為(導(dǎo)致你的產(chǎn)品產(chǎn)生BUG)的變化。
甚至在你不使用測試驅(qū)動(dòng)開發(fā)時(shí),測試還可以降低修改代碼引入的BUG數(shù)量,從而幫你提高代碼的特性和功能。在一款運(yùn)行的應(yīng)用程序中進(jìn)行測試以確保未來的更改不會(huì)改變應(yīng)用的行為。當(dāng)你修復(fù)這些BUG后,你需要添加測試以確保該BUG已經(jīng)被修復(fù)。測試還可以檢測你的代碼,所以有成功和失敗兩種預(yù)期,以覆蓋所有邊界條件。
注意:為一個(gè)沒有考慮到測試的項(xiàng)目添加測試可能會(huì)要求重構(gòu)部分代碼來使測試變得更加簡單?!癢riting Testable Code”包含游泳的編寫可測試代碼的簡單指南。
組件可以包括你的應(yīng)用程序的各部分之間的交互。由于有些測試可能需要很長時(shí)間,所以你可能希望定期或者只在一臺(tái)服務(wù)器上運(yùn)行他們。(你可以組織自己的測試并以多種方式運(yùn)行它們,以滿足不同的需求)。
性能測試
測試的組件可以同時(shí)測試功能和記錄性能。使用XCTest提供的API你可以測量以時(shí)間為基準(zhǔn)的性能測試,對一個(gè)相似的方法或者功能你可以跟蹤性能的提高或者退化。
為了衡量一個(gè)性能測試的成功或者失敗,測試必須有一個(gè)基準(zhǔn)用來評估?;€是運(yùn)行10次以后計(jì)算出來的平均時(shí)間的性能測試。如果與基線相差太多的時(shí)候?yàn)槭 ?**注意:當(dāng)你第一次運(yùn)行性能測試的時(shí)候系統(tǒng)會(huì)提示失敗,因?yàn)榈谝淮芜\(yùn)行的時(shí)候基線是未知的。一旦你設(shè)定了一個(gè)測量準(zhǔn)線,XCTest會(huì)報(bào)告成功或者失敗,并提示相信的結(jié)果信息。**
用戶界面測試
功能測試和性能測試一般都被稱為單元測試,其中的單元是相對于組件和最小的模塊來確定的(大概意思)。單元測試主要是讓相關(guān)的組件能夠按照預(yù)期的那樣交互。從設(shè)計(jì)的角度來看,單元測試是在開發(fā)的時(shí)候編寫的滿足你的預(yù)期。
用戶通過源代碼進(jìn)行界面的交互。界面的交互一般是整合一整個(gè)子系統(tǒng)的操作來實(shí)現(xiàn)預(yù)期的功能。這些很難使用單元測試來進(jìn)行測試,這種特殊的測試被稱為UI測試。
UI測試更貼近于用戶的體驗(yàn)。你可以編寫模擬事件添加到UI測試中,捕捉這些對象的反應(yīng),然后測試正確性和性能和單元測試十分類似。
應(yīng)用程序測試和庫測試
Xcode測試提供兩種測試:應(yīng)用程序測試和庫測試。
應(yīng)用程序測試。應(yīng)用程序測試可以檢查App的代碼組件,例如蘋果測試的官方demo。你可以利用應(yīng)用程序來確保你的UI控件保持原有的位置,并且你的控件和控制器對象能夠和對象模型正確地工作。
庫測試。庫測試可檢查獨(dú)立代碼(不再應(yīng)用程序中運(yùn)行的代碼)的行為是否正確。利用庫測試,你可以將整個(gè)庫的組件放在一起,通常是測試庫的對象和方法。你也可以使用庫測試來執(zhí)行代碼的壓力測試,以確保它在極端的情況下也能正確執(zhí)行(不大可能出現(xiàn)在一個(gè)運(yùn)行的app中)。這些測試可以幫助你生成一個(gè)“健壯的”代碼,即使在沒有預(yù)料的情況下也能運(yùn)行正常。
XCTest-Xcode測試框架
XCTest是一個(gè)Xcode5及以上版本中使用的測試框架。如果你以前使用過Xcode OCUnit測試,你可能會(huì)發(fā)現(xiàn)XCTest和OCUnit有些相似。XCTest是OCUnit更現(xiàn)代化的替代,可以更好的與Xcode集成,為將來Xcode測試功能的改進(jìn)奠定了基礎(chǔ)。Xcode把XCTest.framework并入你的項(xiàng)目,而不是SenTesting.framework。該框架提供可以讓你設(shè)計(jì)測試并在代碼中運(yùn)行的API。
**注意:Xcode包括一個(gè)遷移助手,可用來轉(zhuǎn)換包含OCUnit測試的項(xiàng)目。更多OCUnit想XCTest轉(zhuǎn)換的詳細(xì)信息,請參閱“Transitioning frome OCUnit to XCTest”**
測試從哪里運(yùn)行
當(dāng)你開始創(chuàng)建測試的時(shí)候,記住下面的方法:
- 專注于測試你的代碼的最基礎(chǔ)的功能、模型類、方法,它們與控制器相交互。
應(yīng)用程序的高級框圖很可能會(huì)包含Model、View和Controller類別,對于每個(gè)使用Cocoa和Cocoa Touch的開發(fā)者來說,這是一個(gè)熟悉設(shè)計(jì)模式。當(dāng)你編寫要覆蓋所有Model類別的測試時(shí),你必須要知道App的基礎(chǔ)已經(jīng)進(jìn)行了良好的測試,而且要編寫Controller Classes測試之前,它將帶你接觸你的應(yīng)用程序更復(fù)雜的部分。 - 作為一個(gè)可選的起始點(diǎn),如果你正在編寫一個(gè)框架或庫,你可能想從App接口開始。從那里你可以按照你的方式進(jìn)入內(nèi)部類。
編寫測試類與方法
但你使用測試導(dǎo)航面板往項(xiàng)目中添加測試target的時(shí)候,Xcode會(huì)在測試導(dǎo)航面板里展示除測試類和測試方法。在測試target里是包含測試方法的測試類。
測試target、測試包、測試導(dǎo)航
在學(xué)習(xí)創(chuàng)建測試類前,有必要看看測試導(dǎo)航面板。它對創(chuàng)建和運(yùn)行測試工作極為重要。
測試導(dǎo)航面板羅列了測試包里的所有組件內(nèi)容,并在一個(gè)層次列表里展示出測試類和測試方法。下邊是一個(gè)工程的測試導(dǎo)航面板視圖,包含了多個(gè)測試目標(biāo),展示了測試包、測試類、以及測試方法的嵌套層級。

測試包里可以包含多個(gè)測試類。你可以使用測試類把測試分到相關(guān)的組群里,或者按照功能分,或者按照組織目的分。例如蘋果測試的官方demo,創(chuàng)建了BasicFunctionsTests、AdvancedFunctionsTests、DisplayTests classes三個(gè)類,但它們都屬于Mac_Calc_Tests測試包。

一些測試類型可能會(huì)共享某些類型的setup和teardown,把這些測試整合到類里邊會(huì)更加合理,這樣可以最小化每個(gè)測試方法所需的編寫代碼。
創(chuàng)建測試
可以使用加號(hào)按鈕在導(dǎo)航測試面板中選中“New Test Class”命令來創(chuàng)建新測試類。

基于你在配置頁面鍵入的測試類名,你添加的每一個(gè)類都會(huì)使得一個(gè)名為TestClassName.m的文件被添加到項(xiàng)目中。

注意:所有的測試類都是XCTest框架XCTestCase類的子類。
盡管Xcode會(huì)默認(rèn)的把測試類添加到工程測試項(xiàng)目所創(chuàng)建的組中,你還是可以在項(xiàng)目中組織自己選擇的文件。當(dāng)你按下Next按鈕,標(biāo)準(zhǔn)的Xcode添加文件頁面如下所示:

你可以使用相同的方法在工程導(dǎo)航面板中添加文件。具體使用當(dāng)法詳見“Adding an Existing File or Folder”。
注意:當(dāng)你用Xcode5及以上版本創(chuàng)建工程時(shí),一個(gè)測試target和相關(guān)的測試包都會(huì)被默認(rèn)的創(chuàng)建,名稱根據(jù)工程名獲得。比如創(chuàng)建名為MyApp的項(xiàng)目,則會(huì)自動(dòng)生成一個(gè)名為MyAppTests的測試包,以及一個(gè)名為MyAppTests的測試類,關(guān)聯(lián)在MyAppTests.m實(shí)例文件中。
測試類的結(jié)構(gòu)
測試類包含以下的基礎(chǔ)結(jié)構(gòu):
<code><pre>
*#import <XCTest/XCTest.h>
*@interface SampleCalcTests : XCTestCase
*@end
*@implementation SampleCalcTests
*- (void)setUp {
*[super setUp];
*// Put setup code here. Thismethod is called before the invocation of each test method in the class.
*}
*- (void)tearDown {
*// Put teardown code here. Thismethod is called after the invocation of each test method in the class.
*[super tearDown];
*}
*- (void)testExample {
*// This is an example of afunctional test case.
*// Use XCTAssert and relatedfunctions to verify your tests produce the correct results.
*}
*- (void)testPerformanceExample {
*// This is an example of aperformance test case.
*[self measureBlock:^{
*// Put the code you want tomeasure the time of here.
*}];
*}
@end
</code></pre>
測試類用Objective-C實(shí)現(xiàn)。注意實(shí)現(xiàn)里包含了方法,比如setup和teardown的基本實(shí)例方法。這些方法是必須的。如果類中的所有的測試方法都需要相同的代碼,你可以定制setup和teardown來包含這些代碼。你添加的代碼在每一個(gè)測試方法的之前和之后調(diào)用。你可以選擇添加定制的設(shè)置(+ (void)setUp)和卸載teardown(+ (void)tearDown)方法,它們在類里所有的測試方法的之前和之后調(diào)用。Xcode執(zhí)行測試可以明確這些方法的使用。
測試執(zhí)行的流程
在執(zhí)行測試的過程中,XCTest找到所有集成與XCTestCase(它是測試類)的類,為每一個(gè)類運(yùn)行它們的測試方法。
對于每個(gè)類來說,測試開始于運(yùn)行類的setup方法。對于每個(gè)測試方法來說,一個(gè)新的類實(shí)例被創(chuàng)建,他的實(shí)例setup方法就會(huì)執(zhí)行。在跑完測試方法之后,實(shí)例teardown方法。類中這樣連續(xù)重復(fù)執(zhí)行所有的測試方法。在運(yùn)行了teardown最后的測試方法后,Xcode會(huì)執(zhí)行類teardown方法,并開始下一個(gè)類。這種序列已知重復(fù)直到跑完所有測試類的所有測試方法。
編寫測試方法
你通過編寫測試方法把測試寫到測試類中,一個(gè)測試方法是以test開頭的測試類的實(shí)例方法,沒有參數(shù),返回void,比如TestColorsRed測試方法調(diào)用工程中的代碼,如果代碼沒有產(chǎn)生預(yù)期的效果,那么會(huì)用一系列的斷言API報(bào)錯(cuò)。比如,一個(gè)函數(shù)返回值可能于預(yù)期相比不同,或者你的測試方法使用了某個(gè)不適當(dāng)?shù)姆椒ǘ紝?huì)拋出異常?!癤CTest Assertions”描述了這些情況。
為了是測試方法能夠正常訪問被測代碼,引入正確的頭文件到測試類中很重要。
當(dāng)Xcode運(yùn)行測試時(shí),它調(diào)用的每個(gè)測試方法都是獨(dú)立的。因此每個(gè)方法需要準(zhǔn)備和清理輔助變量、結(jié)構(gòu)以及與主題API進(jìn)行交互的對象等。如果類中所有的測試方法的代碼是相同的,你可以直接把它添加到必走的setup和teardown的實(shí)例方法中,詳見“Test Class Structure”。
下邊是一個(gè)測試方法的模型:
<code><pre>
*- (void)testColorIsRed {
- *// Set up, call test subject API. (Codecould be shared in setUp method.)
- // Test logic and values, assertions reportpass/fail to testing framework.
- // Tear down. (Code could be shared intearDown method.
}
</code></pre>
這里有一個(gè)簡單的測試方法例子,檢查是否成功為SampleCalc創(chuàng)建了CalcView實(shí)例,詳見“快速啟動(dòng)”。
<code><pre>
*- (void) testCalcView {
- // setup
- app = [NSApplication sharedApplication];
- calcViewController =(CalcViewController*)[NSApplication sharedApplication] delegate];
- calcView = calcViewController.view;
- XCTAssertNotNil(calcView, @"Cannot findCalcView instance");
- // no teardown needed
}
</code></pre>
編寫異步操作測試
測試是同步的,因?yàn)橹挥挟?dāng)上一次測試結(jié)束以后才進(jìn)行下一個(gè)測試。但是越來越多的代碼使用異步執(zhí)行。為了處理這些異步調(diào)用執(zhí)行的方法和功能組件,Xcode6增強(qiáng)了包括序列化異步執(zhí)行測試方法的能力,等待異步回調(diào)或者超時(shí)完成。
例如:
<code><pre>
*// Test that the documentis opened. Because opening is asynchronous,
*// use XCTestCase'sasynchronous APIs to wait until the document has
// finished opening.
-(void)testDocumentOpening
{ *// Create anexpectation object.
- *// This test only has one, but it'spossible to wait on multiple expectations.
- *XCTestExpectation *documentOpenExpectation = [selfexpectationWithDescription:@"document open"];
- *NSURL *URL =[[NSBundle bundleForClass:[self class]]
URLForResource:@"TestDocument"withExtension:@"mydoc"];- UIDocumentdoc = [[UIDocument alloc] initWithFileURL:URL];
- *[docopenWithCompletionHandler:^(BOOL success) {
*XCTAssert(success);*// Possibly assert other things here about the document after it hasopened...*// Fulfill the expectation-this will cause -waitForExpectation*// to invoke its completion handler andthen return.*[documentOpenExpectation fulfill];- *}];
- *// The testwill pause here, running the run loop, until the timeout is hit
- *// or all expectations are fulfilled.
- *[selfwaitForExpectationsWithTimeout:1 handler:^(NSError *error) {
*[doc closeWithCompletionHandler:nil];- *}];
*}
</code></pre>
有關(guān)更多異步操作的相信信息,請參閱“XCTest.framework”下的XCTestCase+AsynchronousTesting.h文件。
性能測試
性能測試就是在代碼塊中運(yùn)行10次,收集平均執(zhí)行時(shí)間和和標(biāo)準(zhǔn)的偏差。這些值形成一個(gè)平均值,用來評估和基線對比的成功或者失敗。
**注意:基線是您指定要用于檢測合格與否的瓶價(jià)值。該報(bào)告的UI提供了一種機(jī)制來設(shè)置或者更改基準(zhǔn)值。**
為了實(shí)現(xiàn)性能測試,在Xcode6以后當(dāng)中使用新的XCTest方法的API。
<code><pre>
*- (void)testPerformanceExample{
- *// This is an example of a performance testcase.
- *[self measureBlock:^{
*// Put the code you want to measure thetime of here.- }];
*}
</code></pre>
下面的例子簡單的演示了一個(gè)用計(jì)算器應(yīng)用程序編寫的性能測試的測試速度。一個(gè)measureBlock隨著時(shí)間的增加XCTest迭代。
<code><pre>
*- (void) testAdditionPerformance{
- *[self measureBlock:^{
*// set the initial state*[calcViewController press:[calcViewviewWithTag: 6]]; // 6*// iterate for 100000 cycles of adding2*for (int i=0; i<100000; i++) {*[calcViewController press:[calcViewviewWithTag:13]]; // +*[calcViewController press:[calcViewviewWithTag: 2]]; // 2*[calcViewController press:[calcViewviewWithTag:12]]; // =*}- *}];
}
</code></pre>
運(yùn)行一次性能測試,在測試導(dǎo)航面板的導(dǎo)航器中提供信息。點(diǎn)擊該信息會(huì)顯示運(yùn)行出來的值。結(jié)果顯示包括控制設(shè)置的結(jié)果作為準(zhǔn)線和未來的測試做對比?;€存儲(chǔ)了每個(gè)設(shè)備的配置,所以你相同的測試在不同的設(shè)備上執(zhí)行,會(huì)有不同的準(zhǔn)線。(取決于配置的處理速度,內(nèi)存等等)
注意:性能測試總是在第一次運(yùn)行,直到準(zhǔn)線被設(shè)置在一個(gè)特定的設(shè)備配置中報(bào)告失敗。
有關(guān)性能測試的更多詳細(xì)的信息,請參閱XCTest.framework下的XCTestCase.h文件。
編寫UI測試
創(chuàng)建XCTest UI測試是單元測試的一個(gè)擴(kuò)展對于相同的編程模型。參見“User Interface Testing”。
編寫swift測試
swift控制器和模型不能訪問程序內(nèi)部和框架內(nèi)部聲明。在Xcode6訪問swift的內(nèi)部功能,你需要進(jìn)入公共的切入點(diǎn)來進(jìn)行測試,降低了swift的安全特性。
Xcode7提供了這個(gè)問題的解決方案:
- swift內(nèi)部訪問時(shí),測試通過通知編輯器生成進(jìn)行訪問。編譯器通過一個(gè)新的控制-enable進(jìn)行更改,Xcode在接受到這個(gè)通知的時(shí)候生成。這種行為是控的,對新的項(xiàng)目的默認(rèn)設(shè)置來進(jìn)行設(shè)置。他不需要改變源代碼。
- 通過修改導(dǎo)入頭文件的聲明,來改變測試入口的可見性。使用新的@testable屬性導(dǎo)入,改變你的測試代碼,不需要修改應(yīng)用代碼。
<code><pre>
*import Cocoa
*@NSApplicationMain
*class AppDelegate: NSObject, NSApplicationDelegate {
*@IBOutlet weak var window:NSWindow!
*func foo() {
*println("Hello,World!")
*}
}
</code></pre>
編寫一個(gè)測試類,允許訪問Appdelegate類,修改導(dǎo)入的語句與你的測試代碼使用@testable屬性
<code><pre>
*// Importing XCTestbecause of XCTestCase
*import XCTest
*// Importing AppKitbecause of NSApplication
*import AppKit
*// Importing MySwiftAppbecause of AppDelegate
*@testable importMySwiftApp
*class MySwiftAppTests:XCTestCase {
- *func testExample() {
let appDelegate =NSApplication.sharedApplication().delegate as! AppDelegateappDelegate.foo()- }
}
</code></pre>
有了這個(gè)解決方案,你的swift內(nèi)部代碼能夠完全的被測試方法訪問到。
XCTest斷言
你的測試方法使用XCTest框架提供給的斷言來展示Xcode的測試結(jié)果。所有的斷言都有一個(gè)類似的形式:項(xiàng)目比較或邏輯表達(dá),一個(gè)失敗的結(jié)果字符串格式,和插入到字符串格式中的參數(shù)。
**注意:所有的斷言最后一個(gè)參數(shù)是format…,格式字符串和變量參數(shù)列表。XCTest為所有斷言提供了默認(rèn)的失敗結(jié)果字符串,可以使用參數(shù)傳遞到斷言里。Format字符串提供了可選的額外的失敗自定義描述,就可以進(jìn)一步選擇提供的描述。這個(gè)參數(shù)是可選的,也可以完全忽略。**
例如:
<code><pre>
XCTAssertEqualObjects([calcViewController.displayField stringValue], @"8", @"Part 1 failed.");
</code></pre>
這段簡單明了的描述是說:“Indicate a failure when a string created from the value of the controller’s display field is not the same as the reference string ‘8’”。如果斷言失敗那么Xcode在測試導(dǎo)航面板發(fā)出失敗信號(hào),然后Xcode會(huì)在issues導(dǎo)航面板、源碼編輯器以及其他地方展示失敗的描述。下面是源代碼編輯器典型的斷言結(jié)果:

測試方法可以包含多個(gè)斷言,如果任何斷言包含失敗報(bào)告,那么Xcode都會(huì)發(fā)出測試失敗信號(hào)。
斷言氛圍物種類型:無條件報(bào)錯(cuò)、等價(jià)測試、nil測試、布爾測試以及異常測試。
用類別區(qū)分?jǐn)嘌?/h3>
下面的區(qū)域列出了XCTest斷言。你可以XCTestAssertions.h中獲取更多斷言的信息。
- 無條件報(bào)錯(cuò)
XCTFail生成一個(gè)無條件的報(bào)錯(cuò)
<code><pre>
XCTFail(format...)
</code></pre>
- 等價(jià)測試
XCTAssertEqualObjectes,當(dāng)expresson1不等于expresson2時(shí)報(bào)錯(cuò)(或者一個(gè)對象為空,另一個(gè)對象不為空)
<code><pre>
XCTAssertEqualObjects(expression1, expression2, format...)
</code></pre>
XCTAssertNotEqualObjects. 當(dāng)expression1等于expression2時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertNotEqualObjects(expression1, expression2, format...)
</code></pre>
XCTAssertEqual. 當(dāng)expression1不等于expression2時(shí)報(bào)錯(cuò),這個(gè)測試用于C語言的標(biāo)量。
<code><pre>
XCTAssertEqual(expression1, expression2, format...)
</code></pre>
XCTAssertNotEqual. 當(dāng)expression1等于expression2時(shí)報(bào)錯(cuò),這個(gè)測試用于C語言的標(biāo)量。
<code><pre>
XCTAssertNotEqual(expression1, expression2, format...)
</code></pre>
XCTAssertEqualWithAccuracy. 當(dāng)expression1和expression2之間的差別高于accuracy 將報(bào)錯(cuò)。這種測試適用于floats和doubles這些標(biāo)量,兩者之間的細(xì)微差異導(dǎo)致它們不完全相等,但是對所有的標(biāo)量都有效。
<code><pre>
XCTAssertEqualWithAccuracy(expression1, expression2, accuracy, format...)
</code></pre>
XCTAssertNotEqualWithAccuracy. 當(dāng)expression1和expression2之間的差別低于accuracy將產(chǎn)生失敗。這種測試適用于floats和doubles這些標(biāo)量,兩者之間的細(xì)微差異導(dǎo)致它們不完全相等,但是對所有的標(biāo)量都有效。
<code><pre>
XCTAssertNotEqualWithAccuracy(expression1, expression2, accuracy, format...)
</code></pre>
- Nil(空)測試
XCTAssertNil. 當(dāng)expression參數(shù)非nil時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertNil(expression, format...)
</code></pre>
XCTAssertNotNil. 當(dāng)expression參數(shù)為nil時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertNotNil(expression, format...)
</code></pre>
- Boolean測試
XCTAssertTrue. 當(dāng)expression計(jì)算結(jié)果為false時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertTrue(expression, format...)
</code></pre>
XCTAssert. 當(dāng)expression計(jì)算結(jié)果為false時(shí)報(bào)錯(cuò),與XCTAssertTrue同義。
<code><pre>
XCTAssert(expression, format...)
</code></pre>
XCTAssertFalse. 當(dāng)expression計(jì)算結(jié)果為true報(bào)錯(cuò)。
<code><pre>
XCTAssertFalse(expression, format...)
</code></pre>
- 異常測試
XCTAssertThrows.當(dāng)expression不拋出異常時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertThrows(expression, format...)
</code></pre>
XCTAssertThrowsSpecific.當(dāng)expression針對指定類不拋出異常時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertThrowsSpecific(expression, exception_class, format...)
</code></pre>
XCTAssertThrowsSpecificNamed. 當(dāng)expression針對特定類和特定名字不拋出異常時(shí)報(bào)錯(cuò)。對于AppKit框架或Foundation框架非常有用,拋出帶有特定名字的NSException(NSInvalidArgumentException等等)。
<code><pre>
XCTAssertThrowsSpecificNamed(expression, exception_class, exception_name, format...)
</code></pre>
XCTAssertNoThrow. 當(dāng)expression拋出異常時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertNoThrow(expression, format...)
</code></pre>
XCTAssertNoThrowSpecific. 當(dāng)expression針對指定類拋出異常時(shí)報(bào)錯(cuò)。任意其他異常都可以;也就是說它不會(huì)報(bào)錯(cuò)。
<code><pre>
XCTAssertNoThrowSpecific(expression, exception_class, format...)
</code></pre>
XCTAssertNoThrowSpecificNamed. 當(dāng)expression針對特定類和特定名字拋出異常時(shí)報(bào)錯(cuò)。對于AppKit框架或Foundation框架非常有用,拋出帶有特定名字的NSException(NSInvalidArgumentException等等)
<code><pre>
XCTAssertNoThrowSpecificNamed(expression, exception_class, exception_name, format...)
</code></pre>
運(yùn)行測試并查看結(jié)果
使用Xcode測試導(dǎo)航面板,可以很容易的運(yùn)行測試并查看結(jié)果。有另外幾種運(yùn)行測試的交互方法。Xcode運(yùn)行測試取決于一個(gè)scheme中開啟了哪些test target。測試導(dǎo)航面板讓你無需使用scheme編輯器就能直接控制那些被包含、被開啟或關(guān)閉的test target、類以及方法。
運(yùn)行測試命令
測試導(dǎo)航面板提供了快捷的方法,以將運(yùn)行測試作為編碼流程的一部分。測試同樣可以直接在源代碼編輯器里運(yùn)行或者使用product菜單運(yùn)行。
-
使用測試導(dǎo)航面板
在測試導(dǎo)航面板中,將鼠標(biāo)停在測試包、類或方法名上時(shí),會(huì)出現(xiàn)一個(gè)“Run”按鈕。你可以運(yùn)行某個(gè)特定測試,也可以運(yùn)行一個(gè)類中的測試或運(yùn)行一個(gè)測試包中的所有測試,這取決于列表中的鼠標(biāo)停留位置。
將鼠標(biāo)懸停在測試包名上,并點(diǎn)擊右邊出現(xiàn)的運(yùn)行按鈕來測試一個(gè)包中的所有測試。
將鼠標(biāo)懸停在類名上,并點(diǎn)擊右邊出現(xiàn)的運(yùn)行按鈕來測試一個(gè)類中的所有測試。
將鼠標(biāo)巡艇在測試方法名上,并點(diǎn)擊右側(cè)出現(xiàn)的運(yùn)行按鈕來測試一個(gè)單獨(dú)的測試。
- 使用源代碼編輯器
當(dāng)在源代碼編輯器中打開一個(gè)測試類,每個(gè)測試方法名字旁的邊欄會(huì)明顯的指示器。在指示器上懸停鼠標(biāo),出現(xiàn)一個(gè)運(yùn)行按鈕。點(diǎn)擊按鈕運(yùn)行該測試方法,指示器隨后顯示該測試成功或失敗的狀態(tài)。再次將鼠標(biāo)懸停到指示器上可以再次顯示運(yùn)行按鈕來重復(fù)測試。這種機(jī)制一次只運(yùn)行一個(gè)測試。
注意:出現(xiàn)在@implementation旁邊的指示器同樣也適用于類,允許你運(yùn)行類中所有的測試。
- 使用Product菜單
- Product菜單包括了從鍵盤直接運(yùn)行測試的快捷命令。
- Product>Test運(yùn)行當(dāng)前激活的方案(scheme)。鍵盤快捷鍵是Conmmand-U。
- Product>Build for>Testing和Product>Perform Action>Test without Building。這兩個(gè)命令可以用來構(gòu)建測試并運(yùn)行獨(dú)立于其他的測試。這是簡化構(gòu)建和測試進(jìn)程的快捷命令。對于修改了代碼并在構(gòu)建過程中檢查警告或錯(cuò)誤時(shí),這是特別游泳的,或者如果你知道當(dāng)前的構(gòu)建是最新的,他也可以加速測試過程。鍵盤快捷方式分別是Shift-Command-U和Control-Command-U。
- Product>Perform Action>Test。當(dāng)你編輯一個(gè)測試方法時(shí),這個(gè)動(dòng)態(tài)菜單選項(xiàng)展示當(dāng)前光標(biāo)所處的測試方法,并允許你使用鍵盤快捷鍵方式來運(yùn)行測試。命令的名稱取決于將要運(yùn)行的測試,比如Product>Perform Action>Test testAddition。快捷鍵Control-Opention-Command-U。
注意:除了源代碼編輯器,該命令還基于工程導(dǎo)航面板中的選擇情況運(yùn)行。當(dāng)人和一個(gè)導(dǎo)航面板處于激活狀態(tài),源代碼編輯器就是去了焦點(diǎn),并且該命令將使用任何一個(gè)導(dǎo)航面板中的當(dāng)前選擇作為輸入。在測試導(dǎo)航面板中,可以選擇測試包、類、或方法。在工程導(dǎo)航面板中,可以選擇測試類實(shí)現(xiàn)文件,例如CalcTests.m。
- Product>Perform Action>Test Again。當(dāng)測試方法在調(diào)試/編輯代碼中暴露出問題時(shí),返回最后一個(gè)被執(zhí)行的測試方法非常有用。像Product>Perform Action>Test命令,運(yùn)行的測試名稱在命令中出現(xiàn),例如Product>Perform Action>Test Again testAddition。鍵盤的快捷方式Control-Option-Command-G。
顯示測試結(jié)果
XCTest框架有幾種不同的方式在Xcode中展示測試結(jié)果。下面的屏幕截圖展示了在哪里查看這些測試結(jié)果.
-
在一個(gè)或一組測試運(yùn)行后,你可以在測試導(dǎo)航面板中瀏覽測試通過或者失敗.
如果測試方法被疊加到各自的類中,或測試方法被折疊到測試包中,該標(biāo)識(shí)則反映了封閉測試的集合狀態(tài),表明在這個(gè)類或者包中至少有一個(gè)測試方法不通過。
-
在源代碼編輯器中,你可以瀏覽測試通過或者失敗的標(biāo)識(shí)和調(diào)試信息
- 在報(bào)告導(dǎo)航面板中,可以通過測試運(yùn)行結(jié)果查看。
對于一個(gè)性能測試,單擊時(shí)間列中的值,獲得性能測試的詳細(xì)報(bào)告。你可以通過單擊各個(gè)測試運(yùn)行按鈕,查看10次運(yùn)行的詳細(xì)信息。編輯按鈕可以修改基線和允許通過或者失敗的最大標(biāo)準(zhǔn)偏差。
日志導(dǎo)航面板中,你可以瀏覽相關(guān)的錯(cuò)誤描述和其他一些輸出摘要。點(diǎn)擊走遍的提示箭頭標(biāo)識(shí),可以展開所有的測試運(yùn)行細(xì)節(jié)。
注意:出了左邊展開的三角圖標(biāo),測試失敗項(xiàng)右邊的小圖標(biāo)可以展開顯示更多信息。
-
調(diào)試控制臺(tái)以文本形式展示了測試運(yùn)行的綜合信息。這些信息和日志導(dǎo)航面板中顯示的信息一樣。但如果你已經(jīng)處于debug狀態(tài),那么debug的輸出也會(huì)出現(xiàn)在這里。
使用Schemes(方案)和Test Target(測試目標(biāo))
Xcode Scheme控制著構(gòu)建、運(yùn)行、測試和調(diào)試這些菜單命令的行為。當(dāng)創(chuàng)建Test Target并使用測試導(dǎo)航面板執(zhí)行其他測試系統(tǒng)操作時(shí),Xcode5為我們管理Scheme配置——例如,當(dāng)你開啟或者關(guān)閉一個(gè)測試方法、測試類或測試包時(shí)。使用Xcode Server和持續(xù)集成需要通過設(shè)置Manager Schemes頁面中的復(fù)選框來將一個(gè)Scheme設(shè)置稱共享,并將其連同你的工程和源代碼導(dǎo)出到一個(gè)源文件倉庫。
下面的區(qū)域列出了XCTest斷言。你可以XCTestAssertions.h中獲取更多斷言的信息。
XCTFail生成一個(gè)無條件的報(bào)錯(cuò)
<code><pre>
XCTFail(format...)
</code></pre>
XCTAssertEqualObjectes,當(dāng)expresson1不等于expresson2時(shí)報(bào)錯(cuò)(或者一個(gè)對象為空,另一個(gè)對象不為空)
<code><pre>
XCTAssertEqualObjects(expression1, expression2, format...)
</code></pre>
XCTAssertNotEqualObjects. 當(dāng)expression1等于expression2時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertNotEqualObjects(expression1, expression2, format...)
</code></pre>
XCTAssertEqual. 當(dāng)expression1不等于expression2時(shí)報(bào)錯(cuò),這個(gè)測試用于C語言的標(biāo)量。
<code><pre>
XCTAssertEqual(expression1, expression2, format...)
</code></pre>
XCTAssertNotEqual. 當(dāng)expression1等于expression2時(shí)報(bào)錯(cuò),這個(gè)測試用于C語言的標(biāo)量。
<code><pre>
XCTAssertNotEqual(expression1, expression2, format...)
</code></pre>
XCTAssertEqualWithAccuracy. 當(dāng)expression1和expression2之間的差別高于accuracy 將報(bào)錯(cuò)。這種測試適用于floats和doubles這些標(biāo)量,兩者之間的細(xì)微差異導(dǎo)致它們不完全相等,但是對所有的標(biāo)量都有效。
<code><pre>
XCTAssertEqualWithAccuracy(expression1, expression2, accuracy, format...)
</code></pre>
XCTAssertNotEqualWithAccuracy. 當(dāng)expression1和expression2之間的差別低于accuracy將產(chǎn)生失敗。這種測試適用于floats和doubles這些標(biāo)量,兩者之間的細(xì)微差異導(dǎo)致它們不完全相等,但是對所有的標(biāo)量都有效。
<code><pre>
XCTAssertNotEqualWithAccuracy(expression1, expression2, accuracy, format...)
</code></pre>
XCTAssertNil. 當(dāng)expression參數(shù)非nil時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertNil(expression, format...)
</code></pre>
XCTAssertNotNil. 當(dāng)expression參數(shù)為nil時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertNotNil(expression, format...)
</code></pre>
XCTAssertTrue. 當(dāng)expression計(jì)算結(jié)果為false時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertTrue(expression, format...)
</code></pre>
XCTAssert. 當(dāng)expression計(jì)算結(jié)果為false時(shí)報(bào)錯(cuò),與XCTAssertTrue同義。
<code><pre>
XCTAssert(expression, format...)
</code></pre>
XCTAssertFalse. 當(dāng)expression計(jì)算結(jié)果為true報(bào)錯(cuò)。
<code><pre>
XCTAssertFalse(expression, format...)
</code></pre>
XCTAssertThrows.當(dāng)expression不拋出異常時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertThrows(expression, format...)
</code></pre>
XCTAssertThrowsSpecific.當(dāng)expression針對指定類不拋出異常時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertThrowsSpecific(expression, exception_class, format...)
</code></pre>
XCTAssertThrowsSpecificNamed. 當(dāng)expression針對特定類和特定名字不拋出異常時(shí)報(bào)錯(cuò)。對于AppKit框架或Foundation框架非常有用,拋出帶有特定名字的NSException(NSInvalidArgumentException等等)。
<code><pre>
XCTAssertThrowsSpecificNamed(expression, exception_class, exception_name, format...)
</code></pre>
XCTAssertNoThrow. 當(dāng)expression拋出異常時(shí)報(bào)錯(cuò)。
<code><pre>
XCTAssertNoThrow(expression, format...)
</code></pre>
XCTAssertNoThrowSpecific. 當(dāng)expression針對指定類拋出異常時(shí)報(bào)錯(cuò)。任意其他異常都可以;也就是說它不會(huì)報(bào)錯(cuò)。
<code><pre>
XCTAssertNoThrowSpecific(expression, exception_class, format...)
</code></pre>
XCTAssertNoThrowSpecificNamed. 當(dāng)expression針對特定類和特定名字拋出異常時(shí)報(bào)錯(cuò)。對于AppKit框架或Foundation框架非常有用,拋出帶有特定名字的NSException(NSInvalidArgumentException等等)
<code><pre>
XCTAssertNoThrowSpecificNamed(expression, exception_class, exception_name, format...)
</code></pre>
使用Xcode測試導(dǎo)航面板,可以很容易的運(yùn)行測試并查看結(jié)果。有另外幾種運(yùn)行測試的交互方法。Xcode運(yùn)行測試取決于一個(gè)scheme中開啟了哪些test target。測試導(dǎo)航面板讓你無需使用scheme編輯器就能直接控制那些被包含、被開啟或關(guān)閉的test target、類以及方法。
測試導(dǎo)航面板提供了快捷的方法,以將運(yùn)行測試作為編碼流程的一部分。測試同樣可以直接在源代碼編輯器里運(yùn)行或者使用product菜單運(yùn)行。
使用測試導(dǎo)航面板
在測試導(dǎo)航面板中,將鼠標(biāo)停在測試包、類或方法名上時(shí),會(huì)出現(xiàn)一個(gè)“Run”按鈕。你可以運(yùn)行某個(gè)特定測試,也可以運(yùn)行一個(gè)類中的測試或運(yùn)行一個(gè)測試包中的所有測試,這取決于列表中的鼠標(biāo)停留位置。
將鼠標(biāo)懸停在測試包名上,并點(diǎn)擊右邊出現(xiàn)的運(yùn)行按鈕來測試一個(gè)包中的所有測試。

將鼠標(biāo)懸停在類名上,并點(diǎn)擊右邊出現(xiàn)的運(yùn)行按鈕來測試一個(gè)類中的所有測試。

將鼠標(biāo)巡艇在測試方法名上,并點(diǎn)擊右側(cè)出現(xiàn)的運(yùn)行按鈕來測試一個(gè)單獨(dú)的測試。

當(dāng)在源代碼編輯器中打開一個(gè)測試類,每個(gè)測試方法名字旁的邊欄會(huì)明顯的指示器。在指示器上懸停鼠標(biāo),出現(xiàn)一個(gè)運(yùn)行按鈕。點(diǎn)擊按鈕運(yùn)行該測試方法,指示器隨后顯示該測試成功或失敗的狀態(tài)。再次將鼠標(biāo)懸停到指示器上可以再次顯示運(yùn)行按鈕來重復(fù)測試。這種機(jī)制一次只運(yùn)行一個(gè)測試。

注意:出現(xiàn)在@implementation旁邊的指示器同樣也適用于類,允許你運(yùn)行類中所有的測試。
注意:除了源代碼編輯器,該命令還基于工程導(dǎo)航面板中的選擇情況運(yùn)行。當(dāng)人和一個(gè)導(dǎo)航面板處于激活狀態(tài),源代碼編輯器就是去了焦點(diǎn),并且該命令將使用任何一個(gè)導(dǎo)航面板中的當(dāng)前選擇作為輸入。在測試導(dǎo)航面板中,可以選擇測試包、類、或方法。在工程導(dǎo)航面板中,可以選擇測試類實(shí)現(xiàn)文件,例如CalcTests.m。
XCTest框架有幾種不同的方式在Xcode中展示測試結(jié)果。下面的屏幕截圖展示了在哪里查看這些測試結(jié)果.
在一個(gè)或一組測試運(yùn)行后,你可以在測試導(dǎo)航面板中瀏覽測試通過或者失敗.

如果測試方法被疊加到各自的類中,或測試方法被折疊到測試包中,該標(biāo)識(shí)則反映了封閉測試的集合狀態(tài),表明在這個(gè)類或者包中至少有一個(gè)測試方法不通過。

在源代碼編輯器中,你可以瀏覽測試通過或者失敗的標(biāo)識(shí)和調(diào)試信息


對于一個(gè)性能測試,單擊時(shí)間列中的值,獲得性能測試的詳細(xì)報(bào)告。你可以通過單擊各個(gè)測試運(yùn)行按鈕,查看10次運(yùn)行的詳細(xì)信息。編輯按鈕可以修改基線和允許通過或者失敗的最大標(biāo)準(zhǔn)偏差。

日志導(dǎo)航面板中,你可以瀏覽相關(guān)的錯(cuò)誤描述和其他一些輸出摘要。點(diǎn)擊走遍的提示箭頭標(biāo)識(shí),可以展開所有的測試運(yùn)行細(xì)節(jié)。

注意:出了左邊展開的三角圖標(biāo),測試失敗項(xiàng)右邊的小圖標(biāo)可以展開顯示更多信息。
調(diào)試控制臺(tái)以文本形式展示了測試運(yùn)行的綜合信息。這些信息和日志導(dǎo)航面板中顯示的信息一樣。但如果你已經(jīng)處于debug狀態(tài),那么debug的輸出也會(huì)出現(xiàn)在這里。

Xcode Scheme控制著構(gòu)建、運(yùn)行、測試和調(diào)試這些菜單命令的行為。當(dāng)創(chuàng)建Test Target并使用測試導(dǎo)航面板執(zhí)行其他測試系統(tǒng)操作時(shí),Xcode5為我們管理Scheme配置——例如,當(dāng)你開啟或者關(guān)閉一個(gè)測試方法、測試類或測試包時(shí)。使用Xcode Server和持續(xù)集成需要通過設(shè)置Manager Schemes頁面中的復(fù)選框來將一個(gè)Scheme設(shè)置稱共享,并將其連同你的工程和源代碼導(dǎo)出到一個(gè)源文件倉庫。
Scheme配置方法如下:
-
選擇Scheme menu >Manage Scheme,彈出管理頁。
這個(gè)工程中有兩個(gè)Scheme,一個(gè)用來構(gòu)建應(yīng)用,一個(gè)用來構(gòu)建框架/庫。右側(cè)的Share復(fù)選框用來將Scheme配置為共享,并允許Xcode Server bots使用。
- 在管理頁中,雙擊一個(gè)Scheme,顯示Scheme Editor。一個(gè)Scheme的測試行為標(biāo)識(shí)了你執(zhí)行測試命令時(shí)Xcode執(zhí)行的測試。
注意:測試目標(biāo)、測試類和測試方法所關(guān)聯(lián)的測試導(dǎo)航面板和配置/設(shè)置助手通常維護(hù)所有關(guān)于測試操作的Scheme設(shè)置。
關(guān)于使用、配置和編輯Scheme的更多信息可以查看Scheme Configuration Help,或者視頻WWDC 2012:Working with Scheme and Projects in Xcode。
構(gòu)建測試-測試應(yīng)用、測試庫
應(yīng)用程序在你的應(yīng)用的上下文中運(yùn)行,允許你創(chuàng)建測試,這些測試結(jié)合了不同的類、庫/框架和應(yīng)用功能的角度的行為。庫測試獨(dú)立于你的應(yīng)用,在一個(gè)庫或框架中采用實(shí)驗(yàn)類和方法,來驗(yàn)證它們的行為符合庫的明確要求。
兩種類型的測試包需要不同的構(gòu)建設(shè)置。在新的target助手中通過選擇目標(biāo)參數(shù)來創(chuàng)建test target時(shí),會(huì)執(zhí)行構(gòu)建設(shè)置配置。目標(biāo)助手隨著目標(biāo)下拉菜單顯示。名為SampleCalc的應(yīng)用和名為CalcLibrary的庫可供選擇。

選擇SampleCalc作為該測試目標(biāo)所關(guān)聯(lián)的構(gòu)建產(chǎn)品配置構(gòu)建設(shè)置來測試一個(gè)應(yīng)用。測試的執(zhí)行基于應(yīng)用進(jìn)程,測試在得到SampleCalc你可以根據(jù)自己的偏好改變它。
如果你選擇CalcLibrary作為關(guān)聯(lián)的構(gòu)建產(chǎn)品,目標(biāo)助手將會(huì)在配置構(gòu)建設(shè)置來測試庫。Xcode引導(dǎo)測試運(yùn)行時(shí)上下文和框架/庫,以及你的測試代碼-基于一個(gè)Xcode管理的進(jìn)程。這種情況下默認(rèn)的產(chǎn)品名字來自于庫目標(biāo)(“CalcLibrary Tests”)。同樣你可以基于自己的喜好更改。
默認(rèn)構(gòu)建設(shè)置
大多數(shù)情況下,配置構(gòu)建設(shè)置來測試應(yīng)用或庫所要做的唯一一件事就是選擇正確的測試目標(biāo)。Xcode則自動(dòng)關(guān)注構(gòu)建設(shè)置管理。因?yàn)槟憧赡苡幸粋€(gè)需要復(fù)雜構(gòu)建設(shè)置的功能,所以了解Xcode為應(yīng)用測試和庫測試所建立的標(biāo)準(zhǔn)是非常有用的。
在這里使用官方的測試demo來演示:
-
在工程導(dǎo)航面板中單擊SampleCalc進(jìn)入工程編輯器,然后選擇SampleCalc Tests應(yīng)用測試目標(biāo)。在編輯器的General面板中,有一個(gè)目標(biāo)快捷菜單。該下拉菜單應(yīng)當(dāng)展示SampleCalc為目標(biāo)。
你可以檢查該構(gòu)建設(shè)置是否正確。
-
點(diǎn)擊構(gòu)建設(shè)置,在搜索框中輸入Bundle Loader。針對SampleCalc的應(yīng)用測試被SampleCalc App加載。你可以看到針對Debug和Release的作為自定義參數(shù)的可執(zhí)行文件路徑。搜索Test Host也可以看到相同的路徑。
該工程的庫目標(biāo)名為CalcLibrary,并且已經(jīng)與名為CalcLibraryTests的測試目標(biāo)關(guān)聯(lián)。
-
選擇CalcLibraryTests目標(biāo)并查看General面板。CalcLibrary被作為目標(biāo)。
-
像應(yīng)用測試目標(biāo)一樣,你可以使用build Settings面板查看Bundle Loader和Test Host構(gòu)建設(shè)置,下圖展示Bundle Loader搜索設(shè)置。
在庫測試目標(biāo)的案例中,Bundle Loader和Test Host項(xiàng)目都沒有關(guān)聯(lián)的參數(shù)。這表明Xcode已經(jīng)默認(rèn)正確配置了它們。
測試的目的
應(yīng)用測試在OS X,iOS(真機(jī))和iOS模擬器上運(yùn)行。庫測試運(yùn)行在OS X和iOS模擬器上。Xcode Server可以通過是黨的配置源代碼倉庫,共享Scheme和bot在運(yùn)行OS X Server的Mac上運(yùn)行。更多關(guān)于Xcode Server運(yùn)行目標(biāo)的信息,請查看“Automating the Test Process with Continuous Integration”。
調(diào)試測試
所有標(biāo)準(zhǔn)的Xcode調(diào)試工具在執(zhí)行測試的時(shí)候都可以使用。
測試調(diào)試工作流
要確定的第一件事情就是:造成測試失敗的原因是測試中的代碼有BUG還是執(zhí)行的測試方法存在BUG。測試失敗可以指出一些不同類型的問題,即有你的假設(shè),在測試中的代碼需求,也有測試代碼本身,所以調(diào)試測試可以橫跨幾個(gè)不同的工作流。然而通常你的測試方法是相對較小和直接的,所以最好首先檢查測試的目的是什么,以及它是如何實(shí)現(xiàn)的。
值得注意的一些常見的問題:
測試邏輯是否正確?實(shí)現(xiàn)是否正確?測試方法用作比較基礎(chǔ)使用的字面值,檢查它們的筆誤和粗舞始終是個(gè)好主意。
假設(shè)是什么?例如,你可能在測試方法里使用了錯(cuò)誤的數(shù)據(jù)類型,創(chuàng)建了一個(gè)你所測試的代碼的范圍錯(cuò)誤。
-
是否使用了正確的斷言來報(bào)告,“通過/失敗”狀態(tài)?例如,可能測試的狀態(tài)需要XCTAssertTure而不是XCTAsserFalse。有時(shí)候很容易造成這些錯(cuò)誤。
假設(shè)你的測試假設(shè)是正確的,并且測試方法也正確,那么錯(cuò)誤一定在要測試的代碼中?,F(xiàn)在定位并修復(fù)它。
具體的測試調(diào)試工具
Xcode有幾個(gè)工具專門用來在你測試時(shí)定位和調(diào)試代碼。
-
測試失敗斷點(diǎn)
在斷電導(dǎo)航面板中(BreakPoint Navigator),點(diǎn)擊Add(加號(hào))按鈕,選擇Add Test Failure breakpoint設(shè)置一個(gè)特殊的斷點(diǎn)。
當(dāng)測試方法觸發(fā)了失敗斷言,這個(gè)斷點(diǎn)會(huì)終止測試的運(yùn)行。在測試代碼發(fā)生錯(cuò)誤點(diǎn)擊后立馬停止運(yùn)行,可以讓你快速的找到問題發(fā)生的位置。你可以看看testAddition測試方法,通過為錯(cuò)誤字符串設(shè)置用來比較的參考標(biāo)準(zhǔn),比較字符串被強(qiáng)行斷言為失敗。測試失敗斷點(diǎn)檢測該失敗斷言并停止了該點(diǎn)測試的執(zhí)行。
當(dāng)測試終端,你也就停止了測試的執(zhí)行。然后在斷言前設(shè)置一個(gè)常規(guī)的斷點(diǎn),再次運(yùn)行測試(為了簡單期間,你可以在源代碼編輯器側(cè)欄中點(diǎn)擊“Run”按鈕來運(yùn)行該測試),并繼續(xù)調(diào)試操作來修復(fù)問題。 - 使用工程菜單命令運(yùn)行測試
調(diào)試測試方法時(shí),最好記住菜單命令Project>Perform Action>Test Again和Project>Perform Action>Test。如果你正在測試失敗發(fā)生后編輯修復(fù)代碼,或運(yùn)行你正在編寫的測試方法,它們提供了一個(gè)便捷的方式來測試最后一個(gè)方法。更多信息請查看“Using the Product menu”。
當(dāng)然你也可以始終使用測試導(dǎo)航面板或源代碼編輯器側(cè)邊欄中的“Run”按鈕來運(yùn)行測試,都很方便。 -
輔助編輯器類別
輔助編輯器分類中增加了兩個(gè)專門的分類來運(yùn)行特殊的測試。
- Test Callers category。如果你修復(fù)了一個(gè)飲用測試失敗的方法,你可能會(huì)想要檢查該方法在其他測試中是否被調(diào)用并運(yùn)行成功。帶著這個(gè)問題,在源代碼編輯器中打開輔助編輯器,并從菜單中選擇Test Classes分類。你可以從下拉菜單定位到任何調(diào)用它的測試方法的位置,這樣你就可以運(yùn)行它們,以確保你的修復(fù)沒有造成其他的問題。
- Test Classes Category。該分類和Test Callers類似,不過顯示的是包含測試方法的類列表,這些方法與主源碼編輯器中編輯類的相關(guān)。對于增加測試來說,是一個(gè)非常好的機(jī)會(huì),例如給還沒有被并入測試方法中的新方法增加測試。
- 測試時(shí)的異常斷點(diǎn)
通常當(dāng)異常被異常斷點(diǎn)捕獲時(shí)就會(huì)終止測試執(zhí)行,所以測試運(yùn)行時(shí)通常都會(huì)關(guān)閉異常斷點(diǎn)以避免不適當(dāng)?shù)亩ㄎ粧伋龅臄帱c(diǎn)。當(dāng)你尋找一個(gè)特定的問題并想終止測試來修復(fù)它時(shí)可以打開異常斷點(diǎn)。








