题外话 首先恭喜AlphaGo赢得与李世石九段五番棋的首番,作为下围棋的程序员,我能感受到这盘棋的震撼。其次要夸奖一下segmentfault的新版界面做的很漂亮,如果能配乐就更好了。本文配乐是《最善の一手》。
决定伟大水平和一般水平的关键因素,既不是天赋,也不是经验,而是“刻意练习“的程度。
刻意练习是指为了提高绩效而被刻意设计出来的练习,它要求一个人离开自己的熟练和舒适区域,不断地依据方法去练习和提高。
比如足球爱好者只不过是享受踢球的过程,普通的足球运动员只不过是例行惯事地训练和参加比赛,而顶尖的足球运动员却不断地发现现有能力的不足,并且不断以自己不舒服的方式挑战并练习高难度的动作。
Xcode集成了XCTest测试框架,新建iOS项目的时候,勾选Include Unit Tests,可以建立一个名叫$(PROJECT_NAME)Tests的测试项目。使用XCTest框架进行常规单元测试很简单,就不做讲解了,这里我们主要关注异步测试。
问题是这样的。先看下面的单元测试
-(void)testAsyncTask
{
NSURLSession* session=[NSURLSession sharedSession];
NSURL* url=[NSURL URLWithString:@"https://segmentfault.com"];
NSURLRequest* request=[NSURLRequest requestWithURL:url];
NSURLSessionTask* task=[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
XCTAssertTrue(!error);
}];
[task resume];
}
测试的是一个异步网络任务,在回调XCTAssertTrue(!error)
处打断点,然后运行测试。
运行结果是Test Succeeded,但是回调没有执行,我们的测试也就没有起到预期的作用。
问题出在哪呢?
当执行完[task resume]
后,测试方法就返回了,主线程随之结束,测试程序也就结束了,不会等待异步任务执行完成。
如何解决呢?
如果读者使用cocoapods做依赖管理,可以引入一个名叫JXAsyncTest的异步测试工具pod,在Podfile里添加如下代码
target 'XXXXTest'
pod 'JXAsyncTest'
end
执行命令pod install --verbose
执行成功就完成了JXAsyncTest的安装,然后我们在测试类里引入头文件
#import <JXAsyncTest/JXAsyncTest.h>
对上面的测试方法做如下修改
-(void)testAsyncTask
{
JXAsyncTest* asyncTest=[[JXAsyncTest alloc] initWithTimeoutSeconds:5];
BOOL passed=[asyncTest runTest:^(JXAsyncTest* asyncTest){
NSURLSession* session=[NSURLSession sharedSession];
NSURL* url=[NSURL URLWithString:@"https://segmentfault.com"];
NSURLRequest* request=[NSURLRequest requestWithURL:url];
NSURLSessionTask* task=[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
XCTAssert(!error);
[asyncTest pass];
}];
[task resume];
}];
XCTAssert(passed);
}
仍然在回调处打断点,并运行测试,可以看到这一次回调得到了执行。
有兴趣的读者可以阅读JXAsyncTest的实现。