国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

[iOS翻譯]《iOS7byTutorials》系列:在Xcode5里使用單元測(cè)試(上)

2019-11-14 20:24:41
字體:
供稿:網(wǎng)友

簡(jiǎn)介:

單元測(cè)試是軟件開發(fā)的一個(gè)重要方面。畢竟,單元測(cè)試可以幫你找到bug和崩潰原因,而程序崩潰是Apple在審查時(shí)拒絕app上架的首要原因。

單元測(cè)試不是萬能的,但Apple把它作為開發(fā)工具包的一部分,不僅讓你創(chuàng)作的APP更穩(wěn)定,而且提供了一致、有趣的用戶體驗(yàn),這些都是讓用戶給你五星評(píng)價(jià)的源泉!iOS7提供了一個(gè)升級(jí)的單元測(cè)試框架,讓你在Xcode中運(yùn)行單元測(cè)試更為容易。當(dāng)你完成這一章節(jié),你將學(xué)會(huì)如何給現(xiàn)有app添加測(cè)試——并有可能培養(yǎng)出對(duì)編寫測(cè)試的熱愛!

/*

本文翻譯自《iOS7 by Tutorials》一書的第十一章“Unit Testing in Xcode 5”,想體會(huì)原文精髓的朋友請(qǐng)到Raywenderlich商店支持正版。

——————(博客園、新浪微博)葛布林大帝

*/

 

目錄:

一、單元測(cè)試基礎(chǔ)

二、開始項(xiàng)目

三、下一步何去何從?

四、挑戰(zhàn)

附錄:XCTest斷言參考

 

一、單元測(cè)試基礎(chǔ)

在過去,Xcode引入了一個(gè)叫做OCUnit的開源單元測(cè)試框架。而在Xcode 5里面,Apple發(fā)布了他們自己的的單元測(cè)試框架,叫做XCTest。

如果你已經(jīng)熟悉OCUnit,別擔(dān)心,XCTest是一個(gè)建立在OCUnit之上并且十份相似的API。從OCUnit過渡到XCTest非常簡(jiǎn)單,要做的僅僅是把STFail替換為XCTFail、STAssert替換為XCTAssert等等諸如此類。如果你已經(jīng)熟悉這些基礎(chǔ),可以直接跳到下一節(jié)。

 

 

1.高層次概述

 

 單元測(cè)試有四個(gè)層級(jí)。從上到下,它們分別是:

 

  • 測(cè)試套件(Test suite)
    • 這是項(xiàng)目里測(cè)試的全部集合。在Xcode里,測(cè)試套件被設(shè)置為一個(gè)單獨(dú)的build target。
  • 測(cè)試用例類(Test case classes)
    • 正如你可能所期待的,在一個(gè)面向?qū)ο篌w系中,測(cè)試被整合到類里。在你的app里,每個(gè)測(cè)試類通常對(duì)應(yīng)一個(gè)單獨(dú)類。例如,DeveloperTests類應(yīng)該對(duì)應(yīng)Developer類的測(cè)試。
  • 測(cè)試用例方法(Test case methods)
    • 每個(gè)測(cè)試類包含多種方法,用來測(cè)試類的各種功能。就像一個(gè)方法或函數(shù)應(yīng)該既精簡(jiǎn)又實(shí)用,每個(gè)測(cè)試用例應(yīng)該測(cè)試一個(gè)特定的結(jié)果——并且完全測(cè)試。
  • 斷言(Assertions)
    • 斷言檢查對(duì)應(yīng)預(yù)期結(jié)果的具體條件。如果條件不符合預(yù)期結(jié)果, Xcode會(huì)報(bào)錯(cuò)指出斷言失敗。例如,可以斷言你的Developer 類響應(yīng)“writeKillerApp: message”;如果它沒有,斷言失敗,Xcode報(bào)錯(cuò)。

 

 

理論很美好,但有時(shí)舉例會(huì)更容易闡述事物。用Empty application 模板創(chuàng)建一個(gè)新項(xiàng)目,命名為EmptyApp。 Xcode模板會(huì)自動(dòng)包含一個(gè)叫做EmptyAPPTests的test target,添加到EmptyApp的 app target里,如下圖:

 

注意測(cè)試用例類包含了一個(gè)沒有關(guān)聯(lián)頭文件的.m文件,打開EmptyAppTests.m看看第一個(gè)測(cè)試用例的源代碼。

測(cè)試方法必須以單詞test開始,以便test runner能找到它們。在你的示例項(xiàng)目里,測(cè)試類包含了一個(gè)測(cè)試方法,叫做testExample

 

setUptearDown方法就像守護(hù)在測(cè)試用例周圍的衛(wèi)兵一樣。

把所有對(duì)象的程序設(shè)置代碼或重復(fù)性代碼放到setUp里,使測(cè)試用例方法保持清爽、高效。

類似的,關(guān)閉文件句柄或取消掛起網(wǎng)絡(luò)請(qǐng)求等清理活動(dòng)的方法應(yīng)該放到tearDown里。

 

Test runner 會(huì)依次調(diào)用setUp、testExample和tearDown方法。如果你申明了第二個(gè)測(cè)試方法testSecondExample,Test runner會(huì)依次調(diào)用setUp、testSecondExample,最后是tearDown方法。如果你有多個(gè)測(cè)試方法,setUp和tearDown會(huì)在一個(gè)測(cè)試環(huán)節(jié)調(diào)用多次——每經(jīng)過一個(gè)測(cè)試用例方法調(diào)用一次!

 

這個(gè)故事的寓意是不要放任何處理太慢或處理頻繁的東西到setUp或tearDown方法里——這會(huì)讓你運(yùn)行測(cè)試套件時(shí)面臨漫長的等待

 

 

 

2.創(chuàng)建你的第一個(gè)測(cè)試

 

 

testExample方法只有一個(gè)叫做XCTFail的語句,正如它名字里暗示的:總是會(huì)失敗。這個(gè)語句不是非常有用,你可以寫一個(gè)比它更好的!刪除testExample方法,并添加如下方法:

- (void)test_addition_twoPlusTwo_isFour 
{  XCTAssert(
2 + 2 == 4, @"2 + 2 should be 4 but %d was returned instead", 2+2);}

測(cè)試用例的一個(gè)常用命名標(biāo)準(zhǔn)是:unitOfWork_stateUnderTest_expectedBehavior (工作單元_測(cè)試狀態(tài)_預(yù)期行為)。

在這個(gè)例子里,被測(cè)試的工作單元是加法,測(cè)試狀態(tài)是2 + 2,預(yù)期行為是結(jié)果為4。

所有XCTest斷言都有前綴XCT。XCTAssert是可用于單元測(cè)試的簡(jiǎn)單斷言,第一個(gè)參數(shù)是預(yù)評(píng)估為ture的表達(dá)式,當(dāng)斷言失敗時(shí),其后NSLog風(fēng)格的參數(shù)會(huì)顯示一條消息。

 

確保項(xiàng)目的當(dāng)前target為iphone模擬器,通過窗口頂部目錄的PRoduct -> Test(Command-U)來運(yùn)行測(cè)試,模擬器會(huì)啟動(dòng)并執(zhí)行測(cè)試套件。如果通知處于激活狀態(tài),你會(huì)看到下列確認(rèn)消息:

 

 

為了證實(shí)第一個(gè)單元測(cè)試成功,切換到Test Navigator,箭頭指出了它:

哈哈!翠綠色的小勾旁邊顯示出了你的單元測(cè)試。

你還可以看到邊框空白處菱形圖標(biāo)旁的代碼,如下所示:

這些圖標(biāo)展示關(guān)聯(lián)測(cè)試代碼的狀態(tài):

@implementation旁的綠色小勾表示這個(gè)類測(cè)試通過,test_addition_twoPlusTwo_isFour旁的綠色小勾表示這個(gè)方法測(cè)試通過。

同時(shí),這些圖標(biāo)也是按鈕:

點(diǎn)擊@implementation旁的圖標(biāo)將會(huì)運(yùn)行這個(gè)類的所有測(cè)試,點(diǎn)擊其他測(cè)試方法旁的圖標(biāo)則會(huì)運(yùn)行該測(cè)試方法,試一試吧!

 

現(xiàn)在你已經(jīng)對(duì)測(cè)試的概念和執(zhí)行有了初步了解,是時(shí)候開始本章的示例項(xiàng)目了——測(cè)試開始!

 

二、開始項(xiàng)目

本章的剩余部分你將使用一個(gè)名為Reversi的黑白棋游戲項(xiàng)目,規(guī)則:兩個(gè)玩家,分別代表白方和黑方,輪流在8x8棋盤上落子。通過包圍對(duì)方棋子來吃掉它,游戲結(jié)束時(shí)棋子最多的為勝者。

如何創(chuàng)建這個(gè)游戲,請(qǐng)看:http://www.raywenderlich.com/29228/how-to-develop-an-ipad-board-game-app-part-12

下載本文頁尾提供的示例項(xiàng)目并運(yùn)行,點(diǎn)擊屏幕下方的Vs Computer按鈕與電腦進(jìn)行對(duì)戰(zhàn),感受一下這個(gè)游戲的界面和玩法。

你獲勝了嗎?或者被AI對(duì)手爆出翔?不管怎樣,你的工作不是整日玩游戲——是時(shí)候添加一些有用的測(cè)試到項(xiàng)目里了。

 

1.添加測(cè)試的支持

第一個(gè)需要單元測(cè)試的是GameBoard類。這個(gè)類囊括了8x8棋盤的基本邏輯,64個(gè)單元格中的每個(gè)都有一個(gè)狀態(tài)——空、黑棋或白棋——并且GameBoard實(shí)例讓你能獲取并設(shè)置每一個(gè)方塊的狀態(tài)。 

打開GameBoard.h看一下里面的方法,在開始為現(xiàn)有代碼編寫測(cè)試之前,弄清楚各方法的作用和實(shí)現(xiàn)是一個(gè)好主意。

GameBoard.h,你會(huì)看到下列兩個(gè)方法:

// gets the state of the cell at the given location// raises an NSRangeException if the column or row are out of bounds- (BoardCellState) cellStateAtColumn:(NSInteger)column andRow:(NSInteger)row;// sets the state of the cell at the given location// raises an NSRangeException if the column or row are out of bounds- (void) setCellState:(BoardCellState)state forColumn:(NSInteger)column andRow:(NSInteger)row;

cellStateAtColumn:andRow: 和 setCellState:forColumn:andRow: 由你非常熟悉的getter/setter模式里發(fā)展出來,你的第一個(gè)測(cè)試是執(zhí)行如下動(dòng)作:

  • 初始化一個(gè)GameBoard實(shí)例
  • 設(shè)置cell狀態(tài)
  • 獲取cell狀態(tài)
  • 從指定的cell里獲取cell狀態(tài)

 

第一步是創(chuàng)建一個(gè)GameBoard測(cè)試類,右擊ReversiGameTests分組,選擇 iOS/Cocoa Touch/Objective-C test case class 創(chuàng)建一個(gè)名為GameBoardTests的測(cè)試類,繼承自XCTestCase。

確保你的新測(cè)試用例添加到ReversiGameTests target,如下圖(這個(gè)步驟非常重要,如果沒添加到正確的target里,你的測(cè)試不會(huì)運(yùn)行):

 

打開 GameBoardTests.m 并且刪除 testExample 方法,你不需要它。

然后在 GameBoardTests.m 頂部導(dǎo)入頭文件(這僅僅是讓你的測(cè)試類能夠訪問GameBoard類):GameBoard.h 

#import "GameBoard.h"

 

你需要為你的所有測(cè)試提供一個(gè)GameBoard 實(shí)例,創(chuàng)建一個(gè)實(shí)例變量會(huì)比在每個(gè)測(cè)試?yán)锷昝饕粋€(gè)清爽得多。

GameBoardTests.m 里更新@interface 如下:

@interface GameBoardTests : XCTestCase 
{

  GameBoard *_board;}

現(xiàn)在你有了_board實(shí)例變量,可以開始測(cè)試了。

 

setUp 方法是第一次初始化_board的好地方,修改setUp如下:

- (void)setUp{  [super setUp];  _board = [[GameBoard alloc] init]; }

現(xiàn)在這個(gè)類的所有測(cè)試用例方法都能夠訪問初始化后的_board實(shí)例變量了。

 

2.第一個(gè)測(cè)試

這是你需要為首個(gè)測(cè)試用例添加的所有步驟,添加以下方法到GameBoardTests.m

- (void)test_setAndGetCellState_setValidCell_cellStateChanged {  [_board setCellState:BoardCellStateWhitePiece forColumn:4 andRow:5];
  BoardCellState retrievedState = [_board cellStateAtColumn:4 andRow:5];
  

  XCTAssertEqual(BoardCellStateWhitePiece,           retrievedState,           @"The cell should be white!");}

上面的代碼在(4,5)單元格里設(shè)置了一個(gè)白棋,并且立刻檢索了相同單元格的狀態(tài)。XCTAssertEqual 斷言檢查它們是否相等,如果不相等,你會(huì)看到一個(gè)異常信息,然后你將得知有一些東西需要檢查。

上面代碼的方法名遵循我之前提到的格式,通過這個(gè)方法名,你可以很容易看出它通過設(shè)置正確的單元格位置來測(cè)試setter和getter方法,并期待單元格狀態(tài)的改變。

 

如果你的測(cè)試工作是有計(jì)劃的,確保iPhone和iPad模擬器都測(cè)試,然后運(yùn)行測(cè)試(Command-U)。

切換到Test Navigator,你會(huì)看到一個(gè)綠色小勾表示測(cè)試通過,如下圖:

這看起來只是一個(gè)簡(jiǎn)單的測(cè)試,但是它在調(diào)試錯(cuò)誤里提供了巨大的價(jià)值。

 

在內(nèi)部, GAMEBOARD類使用一個(gè)簡(jiǎn)單的二維數(shù)組來跟蹤8X8棋盤。但如果你曾經(jīng)改變了代表向量或矩陣的數(shù)組,本次測(cè)試將作為回歸測(cè)試,確保interface 的基礎(chǔ)仍在工作。

作為一個(gè)附帶的好處,為現(xiàn)有的類編寫測(cè)試可以大大有助于理解代碼是如何工作的。分析類的方法可以幫助你辨別其功能,并為你編寫測(cè)試提供便利。

 

3.測(cè)試異常

按照設(shè)計(jì)的功能測(cè)試代碼有助于確保其正確性,但也使得你的app“早早失敗或高調(diào)失敗”——那些異常游戲狀態(tài)或無效條件被調(diào)試器很快抓住。

GameBoard.h里cellStateAtColumn:andRow: 和 setCellState:forColumn:andRow: 方法的注釋表明,如果行或列超出棋盤邊框,它們會(huì)彈出錯(cuò)誤。看起來你已經(jīng)找到更多的測(cè)試條件。

添加下列兩個(gè)方法:

- (void)test_setCellState_withInvalidCoords_exceptionThrown {XCTAssertThrowsSpecificNamed([_board setCellState:BoardCellStateBlackPieceforColumn:10andRow:7], NSException,NSRangeException,@"Out-of-bounds board set should raise an exception");}- (void)test_getCellState_withInvalidCoords_exceptionThrown {XCTAssertThrowsSpecificNamed([_board cellStateAtColumn:7 andRow:-10],NSException,NSRangeException,@"Out-of-bounds board access should raise an exception");}

上面的代碼里,test_setCellState_withInvalidCoords_exceptionThrown: 試圖設(shè)置超出范圍的單元格(10,7),同時(shí)test_setCellState_withInvalidCoords_exceptionThrown: 試圖獲取超出范圍的單元格(7,-10)。再次的,方法名已指出在正測(cè)試不正確的坐標(biāo),報(bào)出異常正在意料之中。

 

XCTAssertThrowsSpecificNamed 采用以下四點(diǎn)作為參數(shù):

  • 應(yīng)該報(bào)出異常的表達(dá)式
  • 排除的類
  • 排除的名稱
  • 測(cè)試失敗時(shí)顯示的消息

點(diǎn)擊Command-U運(yùn)行測(cè)試,你應(yīng)該看到以下結(jié)果

這是什么?你希望用出色的代碼通過測(cè)試,但是兩個(gè)錯(cuò)誤標(biāo)記在Issue Navigator上。測(cè)試失敗信息也會(huì)顯示在代碼上,如下圖:

 

所有的測(cè)試失敗消息為:

[GameBoardTests test_getCellState_withInvalidCoords_exceptionThrown] failed: (([_board cellStateAtColumn:7 andRow:-10]) throws <NSException, "NSRangeException">) failed: throwing <NSException, "NSGenericException", "row or column out of bounds"> - Out-of- bounds board access should raise an exception

如果你分解上面的消息,你會(huì)看到你希望的行為是(throws <NSException, "NSRangeException">) ,而實(shí)際發(fā)生的是(throwing <NSException, "NSGenericException">) 。

在這個(gè)例子里,你期待的是NSRangeException ,但接收到的卻是NSGenericException 。

看起來你已經(jīng)做了一些研究!

 

示例項(xiàng)目地址:http://pan.baidu.com/s/1o6x6zxg

 

 

 

 


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 安福县| 云龙县| 逊克县| 平泉县| 泰顺县| 红安县| 无棣县| 京山县| 安泽县| 宾川县| 老河口市| 公主岭市| 安福县| 涿鹿县| 乌鲁木齐市| 阿拉尔市| 忻州市| 平顺县| 日喀则市| 盐边县| 章丘市| 灵武市| 揭东县| 高陵县| 东源县| 大港区| 湖北省| 鄂伦春自治旗| 聂拉木县| 屏东市| 天门市| 乌拉特前旗| 西贡区| 金沙县| 吉木乃县| 普洱| 枝江市| 乐亭县| 中方县| 湘西| 沾益县|