AAA 原则

那,我们来试试看单元测试这条途径。

在Xcode里头建立Project的时候,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");
}

results matching ""

    No results matching ""