iOS 单元测试流程分析和如何异步测试
测试执行的流程
测试类和方法的执行是按照顺序,one by one同步执行的.
执行测试的默认流程是,XCTest
会找到所有的测试类并逐一运行类里的所有测试方法.
当然也可以通过XCode的测试导航控制,只测试某个类或者方法.
对于继承了XCTest
的测试类来说,测试会先执行setup
方法
- 对于每个测试方法来说,上个测试方法的实例对象会被销毁,当前都会重新生成一个当前类的实例
-
每个测试方法都会先执行
setup
方法,在这之后,才会运行我们的测试方法,测试方法执行完成后,会运行teardown
方法 -
所有测试方法的流程都是如上执行的
-
当类里面的最后一个测试方法执行完
teardown
对象方法后,XCode
会执行当前的类方法teardown
,然后开始测试下一个类 -
该流程一直持续到所有的测试方法被测试过后.
写测试方法
测试类中,添加测试方法,均为对象方法,且方法名以test开头,无输入参数和返回结果,举例func testColorIsRed()
测试异步操作
测试是同步按顺序one by one执行的,为了处理测试异步操作的情况,XCTest
在XCode 6之后提供了串行异步去执行测试方法,会在当前方法等待,直到异步方法执行完成或者超时.
如何测试异步方法,在异步方法完成之后才进行下一步操作呢?需要类XCTestExpectation
创建XCTestExpectation
实例,通过方法expectation(description:)
,一个测试方法里,可以有多个expectations,
创建expectation后,可以通过fullfill
标记异步操作的完成,或者通过waitForExpectationsWithTimeout : handler:
方法,进行一个超时时间的监听.如果在超时时间过后,exception没有被标记为完成,则测试失败,进入timeout的回调.
下面是例子
// 测试异步操作
// 使用 XCTestCase的异步API监听,直到异步操作完成
- (void)testDocumentOpening
{
// 创建expectation对象
// 下面的例子只有一个expectation, 但是在实际开发中,可以创建多个,并且会等待直到全部完成
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);
// 对结果进行判断,进行处理或者抛出异常
// 结束当前的expectation,该操作会触发 waitForExpectation 方法
[documentOpenExpectation fulfill];
}];
// 测试会暂时停止,直到超时或者expectation被完成
[self waitForExpectationsWithTimeout:1 handler:^(NSError *error) {
[doc closeWithCompletionHandler:nil];
}];
}
巧用断言
断言的作用在于,当测试的结果不满足需求时,通过断言来宣布当前测试失败,一个测试方法中可以有多个断言,只要其中一个失败,及视为测试失败.断言的使用非常简单,系统提供了以下几种类型
- 无条件失败:
XCTFail(format...)
,该断言会直接宣布测试失败 - 等式失败:
XCTAssertEqualObjects
等形式,不一一列举,当等式不满足时,宣布失败 - 空值测试
-
XCTAssertNil
不为空时失败 -
XCTAssertNotNil
为空时失败
-
- 布尔测试
-
XCTAssertTrue(expression, format...)
不为ture时失败 -
XCTAssertFalse(expression, format...)
不为false时失败
-