當(dāng)使用測試導(dǎo)航器將測試目標(biāo)添加到項目時侥衬,Xcode在測試導(dǎo)航器中顯示該目標(biāo)的測試類和方法诲侮。在測試目標(biāo)中是包含測試方法的測試類。本章介紹如何創(chuàng)建測試類和編寫測試方法屹培。
測試目標(biāo)默穴,測試包和測試導(dǎo)航器
在查看創(chuàng)建測試類之前,值得再看一下測試導(dǎo)航器惫谤。使用它是創(chuàng)建和使用測試的核心壁顶。
向項目添加測試目標(biāo)創(chuàng)建測試包珠洗。測試導(dǎo)航器列出項目中所有測試包的源代碼組件溜歪,在分層列表中顯示測試類和測試方法。下面是一個具有兩個測試目標(biāo)的項目的測試導(dǎo)航器視圖许蓖,顯示了測試包蝴猪,測試類和測試方法的嵌套層次結(jié)構(gòu)调衰。
測試包可以包含多個測試類。你可以使用測試類將測試分為相關(guān)組自阱,無論是出于功能還是組織目的嚎莉。例如,對于計算器的例子項目可以創(chuàng)建BasicFunctionsTests沛豌,AdvancedFunctionsTests和DisplayTests類趋箩,各部分Mac_Calc_Tests測試包。
一些類型的測試可能共享某些類型的設(shè)置和拆卸要求叫确,使得將這些測試集中到類中是明智的,其中一組設(shè)置和拆卸方法可以最小化為每個測試方法編寫多少代碼芍锦。
創(chuàng)建測試類
注意: 本章著重介紹單元測試類和方法竹勉。創(chuàng)建UI測試的目標(biāo),類和方法娄琉,以及如何從單元測試工作不同次乓,在討論用戶界面測試。
你可以使用測試導(dǎo)航器中的添加按鈕(+)來創(chuàng)建新的測試類孽水。
你可以選擇添加單元測試類或UI測試類票腰。選擇其中之一后,Xcode會顯示一個文件類型選擇器女气,其中選擇了所選文件模板類型丧慈。“新建單元測試類”模板在下圖中突出顯示主卫。單擊下一步繼續(xù)你的選擇逃默。
你添加的每個測試類都會根據(jù)你在配置表中輸入的測試類名稱,將一個名為TestClassName .m 的文件添加到項目中簇搅。
注意: 所有測試類都是XCTest框架XCTestCase提供的子類完域。
盡管默認(rèn)情況下Xcode將測試類實現(xiàn)文件組織到為項目的測試目標(biāo)創(chuàng)建的組中,但是你可以根據(jù)自己的選擇組織項目中的文件瘩将。當(dāng)你按下一步按鈕時吟税,標(biāo)準(zhǔn)Xcode添加文件表遵循此配置。
注意: 創(chuàng)建新項目時姿现,默認(rèn)情況下將為你創(chuàng)建測試目標(biāo)和關(guān)聯(lián)的測試包肠仪,其名稱來自項目名稱。例如备典,創(chuàng)建名為的新項目會MyApp自動生成名為的測試包MyAppTests和MyAppTests使用關(guān)聯(lián)的MyAppTests.m實現(xiàn)文件命名的測試類异旧。
測試類結(jié)構(gòu)
測試類具有以下基本結(jié)構(gòu):
#import <XCTest/XCTest.h>
@interface SampleCalcTests : XCTestCase
@end
@implementation SampleCalcTests
- (void)setUp {
[super setUp];
// 在調(diào)用類中的每個測試方法之前調(diào)用此方法。
}
- (void)tearDown {
//此方法在調(diào)用類中的每個測試方法后調(diào)用提佣。
[super tearDown];
}
- (void)testExample {
//這是一個功能測試用例的例子吮蛹。
//使用XCTAssert和相關(guān)函數(shù)來驗證測試是否產(chǎn)生正確的結(jié)果荤崇。the correct results.
}
- (void)testPerformanceExample {
//這是一個性能測試用例的例子。
[self measureBlock:^{
//放你想要測量的代碼這里的時間潮针。
}];
}
@end
測試類在本例中是在Objective-C中實現(xiàn)的术荤,但也可以在Swift中實現(xiàn)。
注意: 本文中的實現(xiàn)示例都是使用Objective-C編寫的每篷,以保持一致性瓣戚。
Swift與使用XCTest和實現(xiàn)測試方法完全兼容。也可以使用所有Swift和Objective-C跨語言實現(xiàn)功能焦读。
請注意带兜,實現(xiàn)包含用于實例設(shè)置和拆卸的方法,具有基本實現(xiàn); 這些方法不是必需的吨灭。如果類中的所有測試方法都需要相同的代碼刚照,你可以自定義setUp并tearDown包括它。你添加的代碼在每個測試方法運(yùn)行之前和之后運(yùn)行喧兄。你可以選擇為類setup(+ (void)setUp)和teardown(+ (void)tearDown)添加自定義的方法无畔,它們在類中的所有測試方法之前和之后運(yùn)行。
測試執(zhí)行流程
在默認(rèn)情況下吠冤,當(dāng)運(yùn)行測試時浑彰,XCTest將查找所有測試類,并為每個類運(yùn)行其所有測試方法拯辙。(所有測試類繼承自XCTestCase郭变。)
注意: 有些選項可用于更改XCTest運(yùn)行的測試。你可以使用測試導(dǎo)航器或編輯方案禁用測試涯保。你還可以使用測試導(dǎo)航器或源代碼編輯器水槽中的運(yùn)行按鈕運(yùn)行組中的一個測試或一組測試诉濒。
對于每個類,測試從運(yùn)行類設(shè)置方法開始夕春。對于每個測試方法未荒,將分配該類的一個新實例,并執(zhí)行其實例設(shè)置方法及志。之后它運(yùn)行測試方法片排,然后是實例拆卸方法。該序列對于類中的所有測試方法重復(fù)速侈。在類中的最后一個測試方法拆卸已經(jīng)運(yùn)行之后率寡,Xcode執(zhí)行類拆卸方法并移動到下一個類。此序列重復(fù)倚搬,直到所有測試類中的所有測試方法都已運(yùn)行冶共。
寫測試方法
通過編寫測試方法將測試添加到測試類。測試方法是測試類的實例方法,以前綴“test”開始比默,不帶參數(shù)幻捏,并返回void盆犁,例如(void)testColorIsRed()命咐。測試方法在項目中執(zhí)行代碼,如果代碼沒有產(chǎn)生預(yù)期結(jié)果谐岁,則使用一組斷言API報告失敗醋奠。例如,函數(shù)的返回值可能與預(yù)期值進(jìn)行比較伊佃,或者測試可能斷言在一個類中不當(dāng)使用方法會拋出異常窜司。XCTest斷言描述了這些斷言。
對于測試方法來訪問要測試的代碼航揉,將相應(yīng)的頭文件導(dǎo)入到測試類中塞祈。
當(dāng)Xcode運(yùn)行測試時,它獨立調(diào)用每個測試方法帅涂。因此议薪,每個方法必須準(zhǔn)備和清理與主題API交互所需的任何輔助變量,結(jié)構(gòu)和對象媳友。如果此代碼對類中的所有測試方法都是通用的斯议,那么可以將其添加到
測試類結(jié)構(gòu)中描述
的必需setUp和tearDown實例方法。
這里是單元測試方法的模型:
- (void)testColorIsRed {
//設(shè)置醇锚,調(diào)用測試主題API哼御。(代碼可以在setUp方法中共享。)
//測試邏輯和值焊唬,斷言報告通過/失敗到測試框架恋昼。
// 拆除。(代碼可以在tearDown方法中共享赶促。
}}
下面是一個簡單的測試方法示例焰雕,用于檢查是否CalcView為SampleCalc成功創(chuàng)建了實例,該應(yīng)用程序顯示在快速入門章節(jié)中:
- (void)testCalcView {
// 建立
app = [NSApplication sharedApplication];
calcViewController =(CalcViewController *)[NSApplication sharedApplication] delegate];
calcView = calcViewController.view;
XCTAssertNotNil(calcView芳杏,@“找不到CalcView實例”);
//沒有拆卸需要
}}
寫異步操作測試
測試同步執(zhí)行矩屁,因為每個測試獨立地被一個接一個地調(diào)用。但越來越多的代碼異步執(zhí)行爵赵。為了處理調(diào)用異步執(zhí)行方法和函數(shù)的測試組件吝秕,XCTest在Xcode 6中得到了增強(qiáng),包括通過等待異步回調(diào)或超時的完成來串行化測試方法中的異步執(zhí)行的能力空幻。
源示例:
//測試文檔是否打開烁峭。因為打開是異步的,
//使用XCTestCase的異步API等待文檔
//完成打開。
- (void)testDocumentOpening
{
//創(chuàng)建期望對象约郁。
//這個測??試只有一個缩挑,但是可以等待多個期望。
XCTestExpectation * documentOpenExpectation = [self expectationWithDescription:@“document open”];
NSURL * URL = [[NSBundle bundleForClass:[self class]]
URLForResource:@“TestDocument”withExtension:@“mydoc”];
UIDocument * doc = [[UIDocument alloc] initWithFileURL:URL];
[doc openWithCompletionHandler:^(BOOL success){
XCTAssert(success);
//可能在文檔打開后在這里關(guān)于其他事情...
//滿足期望 - 這將導(dǎo)致-waitForExpectation
//調(diào)用它的完成處理程序鬓梅,然后返回供置。
[文檔打開Expectation履行];
}];
//測試將在這里暫停,運(yùn)行運(yùn)行循環(huán)绽快,直到超時被擊中
//或所有期望得到滿足芥丧。
[self waitForExpectationsWithTimeout:1 handler:^(NSError * error){
[doc closeWithCompletionHandler:nil];
}];
}}
有關(guān)編寫異步操作方法的更多詳細(xì)信息,請參見XCTestExpectation參考文檔坊罢。
寫作性能測試
性能測試需要一段代碼续担,你要評估它并運(yùn)行它十次,收集平均執(zhí)行時間和運(yùn)行的標(biāo)準(zhǔn)偏差活孩。這些單獨測量的平均值形成測試運(yùn)行的值物遇,然后可以將其與基線進(jìn)行比較以評估成功或失敗。
注意: 基線是你指定用于評估測試通過或失敗的值憾儒。報表UI提供了設(shè)置或更改基準(zhǔn)值的機(jī)制
要實現(xiàn)性能測量測試询兴,你需要在Xcode 6和更高版本中使用XCTest中的新API編寫方法。
- (void)testPerformanceExample {
//這是一個性能測試用例的例子航夺。
[self measureBlock:^ {
//放你想要測量的代碼這里的時間蕉朵。
}];
}}
以下簡單示例顯示使用計算器示例應(yīng)用程序?qū)懭霚y試添加速度的性能測試。A measureBlock:與XCTest的時間迭代一起添加阳掐。
- (void)testAdditionPerformance {
[self measureBlock:^ {
//設(shè)置初始狀態(tài)
[calcViewController press:[calcView viewWithTag:6]]; // 6
//迭代100000個循環(huán)的添加2
for(int i = 0; i <100000; i ++){
[calcViewController press:[calcView viewWithTag:13]]; // +
[calcViewController press:[calcView viewWithTag:2]]; // 2
[calcViewController press:[calcView viewWithTag:12]]; // =
}}
}];
}}
性能測試一旦運(yùn)行始衅,就會在查看實施文件時在源編輯器中,在測試導(dǎo)航器中以及在報告導(dǎo)航器中提供信息缭保。單擊信息將顯示各個運(yùn)行值汛闸。結(jié)果顯示包括將結(jié)果設(shè)置為測試的未來運(yùn)行的基線的控制∫章睿基準(zhǔn)按每個設(shè)備配置存儲诸老,因此你可以在幾個不同的設(shè)備上執(zhí)行相同的測試,并且每個設(shè)備根據(jù)特定配置的處理器速度钳恕,內(nèi)存等保持不同的基線别伏。
注意: 性能測量測試始終在第一次運(yùn)行時報告故障,直到在特定設(shè)備配置上設(shè)置基準(zhǔn)值忧额。
有關(guān)性能測量測試的編寫方法的更多詳細(xì)信息厘肮,請參見XCTestCase參考文檔。
編寫UI測試
使用XCTest創(chuàng)建UI測試是與創(chuàng)建單元測試相同的編程模型的擴(kuò)展睦番。
總體上使用類似的操作和編程方法类茂。
工作流和實現(xiàn)的差異集中在使用UI記錄和XCTest UI測試API耍属,在用戶界面測試中描述盅称。
使用Swift編寫測試Swift訪問控制模型(如Swift編程語言(Swift 3.1)的訪問控制部分所述)阻止外部實體訪問在應(yīng)用程序或框架中聲明為內(nèi)部的任何東西唯灵。默認(rèn)情況下嗤详,為了能夠從測試代碼訪問這些項目挪哄,你需要將他們的訪問級別提升為至少公開,從而降低Swift的類型安全性的好處不铆。
Xcode為這個問題提供了一個兩部分的解決方案:
1.當(dāng)你將Enable Testability構(gòu)建設(shè)置設(shè)置為時Yes仲墨,默認(rèn)情況下對于新項目中的測試構(gòu)建為true括荡,Xcode -enable-testing在編譯期間包含標(biāo)志厦瓢。這使得編譯模塊中聲明的Swift實體有資格獲得更高級別的訪問提揍。
2.將@testable屬性添加到在啟用了測試的情況下編譯的模塊的導(dǎo)入語句中時啤月,將激活該范圍中該模塊的提升式訪問煮仇。標(biāo)記為內(nèi)部或公共的類和類成員表現(xiàn)為好像被標(biāo)記為打開。被標(biāo)記為內(nèi)部的其他實體好像被宣布為公開谎仲。
請注意浙垫,你不以任何方式更改源代碼。你只修改編譯(通過拋出一個標(biāo)志)和測試代碼(通過修改import語句)郑诺。例如夹姥,對于AppDelegate名為“MySwiftApp”的應(yīng)用程序,請考慮像此實現(xiàn)一樣的Swift模塊辙诞。
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
func foo() {
println("Hello, World!")
}
}
要編寫允許訪問類的測試類辙售,AppDelegate請使用import屬性修改測試代碼中的@testable語句,如下所示:
// 導(dǎo)入基于XCTestCase的XCTest
import XCTest
// 導(dǎo)入基于NSApplication的AppKit
import AppKit
//導(dǎo)入基于AppDelegate的 MySwiftApp
@testable import MySwiftApp
class MySwiftAppTests: XCTestCase {
func testExample() {
let appDelegate = NSApplication.sharedApplication().delegate as! AppDelegate
appDelegate.foo()
}
}
有了這個解決方案飞涂,你的Swift應(yīng)用程序代碼的內(nèi)部函數(shù)可以完全訪問你的測試類和方法旦部。為@testable入口授予的訪問權(quán)限確保其他非測試客戶端不違反Swift的訪問控制規(guī)則,即使在編譯測試時较店。此外士八,因為你的發(fā)布版本不支持可測試性,所以你的模塊的常規(guī)用戶(例如梁呈,如果你分發(fā)框架)無法通過這種方式訪問??內(nèi)部實體婚度。
注意: @testable僅提供內(nèi)部功能的訪問; 文件私有和私有聲明在使用時在其通常范圍之外是不可見的@testable.
XCTest斷言
你的測試方法使用XCTest框架提供的斷言來呈現(xiàn)Xcode顯示的測試結(jié)果。所有斷言具有類似的形式:要比較的項目或邏輯表達(dá)式官卡,失敗結(jié)果字符串格式蝗茁,以及要插入字符串格式的參數(shù)。
注意: 所有斷言的最后一個參數(shù)是format...一個格式字符串及其變量參數(shù)列表寻咒。XCTest為所有斷言提供一個默認(rèn)的失敗結(jié)果字符串哮翘,使用傳遞給斷言的參數(shù)進(jìn)行匯編。該format字符串提供了除了提供的描述之外還可以選擇提供的故障的附加的自定義描述的能力仔涩。此參數(shù)是可選的忍坷,可以省略。
例如,查看快速入門中提供的testAddition方法中的此斷言:
XCTAssertEqualObjects([calcViewController.displayField stringValue], @"8", @"Part 1 failed.");
閱讀這個簡單的語言佩研,它說“當(dāng)從控制器的顯示字段的值創(chuàng)建的字符串不同于參考字符串'8'時柑肴,指示失敗⊙恚” Xcode信號與測試導(dǎo)航器中的失敗指示器如果斷言失敗晰骑,Xcode還會在問題導(dǎo)航器,源代碼編輯器和其他位置顯示帶有描述字符串的故障绊序。源編輯器中的典型結(jié)果如下所示:
測試方法可以包括多個斷言硕舆。如果任何斷言包含報告失敗,Xcode會發(fā)出測試方法失敗的信號骤公。
斷言分為五類:
無條件失敗抚官。使用這個,當(dāng)簡單地到達(dá)特定分支的代碼表示失敗阶捆。這個類別中唯一的斷言是XCTFail凌节。
平等測試。使用這些來斷言兩個項目之間的關(guān)系洒试。例如倍奢,XCTAssertEqual斷言兩個表達(dá)式具有相同的值,而XCTAssertEqualWithAccuracy斷言兩個表達(dá)式在一定精度內(nèi)具有相同的值垒棋。這個類別還包括不平等的測試卒煞,例如XCTAssertNotEqual和XCTAssertGreaterThan。
布爾檢驗叼架。使用這些來斷言布爾表達(dá)式以某種方式計算畔裕,例如使用XCTAssertTrue或XCTAssertFalse。
無測試碉碉。使用這些來斷言項目是或不是nil柴钻,例如使用XCTAssertNil或XCTAssertNotNil。
異常測試垢粮。使用這些來斷言評估表達(dá)式是否生成異常贴届。你尋找任何異常拋出XCTAssertThrows,或者你可以尋找一個具有斷言的特定異常XCTAssertThrowsSpecific蜡吧。你還可以斷言反向毫蚓,當(dāng)評估表達(dá)式時,使用類似的函數(shù)沒有拋出異常XCTAssertNoThrow昔善。
該XCTest框架參考包含了所有可用的斷言功能的完整枚舉元潘。
使用Objective-C和Swift的斷言
當(dāng)使用XCTest斷言時,你應(yīng)該知道當(dāng)編寫Objective-C(和其他基于C語言)代碼和編寫Swift代碼時君仆,斷言的兼容性和行為的根本區(qū)別翩概。了解這些差異使得編寫和調(diào)試測試更容易
執(zhí)行等式測試的XCTest斷言分為比較對象和比較非對象的那些牲距。例如,XCTAssertEqualObjects測試兩個解析為對象類型的XCTAssertEqual
表達(dá)式之間的相等性钥庇,同時測試兩個解析為標(biāo)量類型值的表達(dá)式之間的相等性牍鞠。通過在描述中包括“此測試是針對標(biāo)量”,在XCTest斷言列表中標(biāo)記此差異评姨。使用“標(biāo)量”標(biāo)記斷言通知你基本區(qū)別难述,但它不是對哪些表達(dá)式類型是兼容的確切描述。
對于Objective-C中吐句,標(biāo)記為標(biāo)量類型斷言可與能與相等比較運(yùn)營商使用的類型可以使用:==胁后,!=,<=嗦枢,<攀芯,>=,和>净宵。如果表達(dá)式解析為使用這些運(yùn)算符的任何C類型敲才,結(jié)構(gòu)或數(shù)組比較裹纳,它被認(rèn)為是一個標(biāo)量择葡。
對于Swift,標(biāo)記為標(biāo)量的斷言可以用于比較符合Equatable協(xié)議的任何表達(dá)式類型(對于所有“等于”和“不等于”的斷言)和Comparable協(xié)議(對于“大于”和“小于”的斷言)剃氧。此外敏储,標(biāo)標(biāo)量斷言有覆蓋的[T]和[K:V],在那里T朋鞍,K和V符合Equatable或Comparable協(xié)議已添。例如,等價類型的數(shù)組與其XCTAssertEqual(::_:file:line:)鍵和值都是可比較類型的字典兼容XCTAssertLessThan(::_:file:line:)滥酥。
注意: 在Swift中更舞,NSObject符合Equatable,因此使用XCTAssertEqualObjects工程坎吻,但不是必需的缆蝉。
在你的測試中使用XCTest斷言也不同于Objective-C和Swift,因為語言在處理數(shù)據(jù)類型和隱式轉(zhuǎn)換方面有所不同瘦真。
對于Objective-C刊头,在XCTest實現(xiàn)中使用隱式轉(zhuǎn)換允許比較操作獨立于表達(dá)式的數(shù)據(jù)類型,并且不檢查輸入數(shù)據(jù)類型诸尽。
對于Swift原杂,不允許隱式轉(zhuǎn)換,因為Swift對類型安全更嚴(yán)格; 兩個參數(shù)的比較必須是相同的類型您机。類型不匹配在編譯時和源編輯器中標(biāo)記穿肄。