Skip to content

Latest commit

 

History

History
73 lines (61 loc) · 3.24 KB

3a.md

File metadata and controls

73 lines (61 loc) · 3.24 KB

AAA 原則

那,我們來試試看單元測試這條途徑。

在 Xcode 裡頭建立專案的時候,Xcode 會幫我們的 App 同時建立一個單元測試 的 Bundle—其實蘋果也鼓勵你寫單元測試—在這個 Bundle 中,會出現一個繼承 自 XCTestCase 的 class,在裡頭撰寫任何用 test 開頭的 method,像 -testHit,都是一條test case。也就是,我們寫測試的時候,就是寫出一群 用 test 為開頭的 method。

Xcode 從 5.1 版現在的測試框架叫做 XCTest,在這之前則是使用一套叫做 OCUnit 的測試框架(這邊的 OC 其實就是 Objective-C 的意思),除此之外, iOS 與 Mac OS X 平台上還有許多有名的測試框架,像是 GHUnitKiwi 等等。我們在這邊只先講解 XCUnit,如果你對單元測試有些心得,覺得 XCUnit 已經無法滿足你的需求,不 妨也可以試試看其他的測試框架。

在撰寫測試的時候,基本原則是一次只測試一項 function 或 method,同時一 個 test case 會包含所謂的 AAA 原則:Arrange、Act 與 Assert。

  • Arrange: 先設定我們在這次測試中,所預期的結果
  • Act: 就是我們想要測試的 function 或 method
  • Assert: 確認在 Action 發生後,確認在執行了想要測試 function 或 method 後,的確符合我們在 Arrange 階段設定的目標

舉個例子,我們預期一條長度為 6 、正在往左邊移動的蛇,在先往上走一格、 再往右走一格、再往下走一格之後,這條蛇的頭一定會撞到自己的身體,如果我 們的程式說蛇頭沒有撞到,就一定有 Bug。就可以拆解成:

  • Arrange: 頭應該會撞到身體
  • Action: 讓蛇執行往上右下移動的動作
  • Assert: 確認頭真的撞到身體了

這個 case 或許會像這樣:

- (void)testHit
{
	KKSnake *snake = [[KKSnake alloc]
	  initWithWorldSize:KKMakeSnakeWorldSize(10, 10) length:6];
	[snake changeDirection:KKSnakeDirectionUp];[[snake move];
	[snake changeDirection:KKSnakeDirectionRight];[snake move];
	[snake changeDirection:KKSnakeDirectionDown];[snake move];
	XCTAssertEqual([snake isHeadHitBody], YES, @"must hit the body.");
}

如果我們想要測試「蛇的尾巴加長」這段程式是否正常,大概會這麼寫:原本這 條蛇的長度為 2,尾巴位在 (6, 5),假如蛇的身體要加長兩格,我們預期蛇的 長度變成 4,尾巴位在 (8, 5)。

- (void)testIncreaseLength
{
	ZBSnake *snake = [[ZBSnake alloc] initWithWorldSize:ZBMakeSnakeWorldSize(10, 10) length:2];
	XCTAssertEqual((int)[snake.points count], 2, @"Length must be 2 but %d", [snake.points count]);
	NSInteger x;
	NSInteger y;
	x = [snake.points[[snake.points count] - 1] snakePointValue].x;
	y = [snake.points[[snake.points count] - 1] snakePointValue].y;
	XCTAssertEqual(x, 6, @"must be 6");
	XCTAssertEqual(y, 5, @"must be 5");

	[snake increaseLength:2];
	XCTAssertEqual((int)[snake.points count], 4, @"Length must be 4 but %d", [snake.points count]);
	x = [snake.points[[snake.points count] - 1] snakePointValue].x;
	y = [snake.points[[snake.points count] - 1] snakePointValue].y;
	XCTAssertEqual(x, 8, @"must be 8");
	XCTAssertEqual(y, 5, @"must be 5");
}