Xcode標準のテストライブラリがうまいことやってくれないせいで、非同期処理のテストを書く場合に待ちの処理を自分で書いてあげないといけません。

最近のすごくいい感じの拡張が紹介されたのでこれを使うとなかなかいい感じです。

Objective-Cで非同期処理のテストをシンプルに書く方法 - TOKOROM BLOGObjective-Cで非同期処理のテストをシンプルに書く方法 - TOKOROM BLOGはてなブックマーク - Objective-Cで非同期処理のテストをシンプルに書く方法 - TOKOROM BLOG

ですが、実際はそこまでやらなくてもSDK標準の機能だけでも簡単に実装できます。サンプルコードは以下の通り。

- (void)testExample
{
    CFRunLoopRef rl = CFRunLoopGetCurrent();

    NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://blog.piyo.tech/"]];
    NSOperationQueue *queue = [NSOperationQueue new];
    [NSURLConnection sendAsynchronousRequest:req queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        NSLog(@"complete");
        XCTAssert(NO);
        CFRunLoopStop(rl);
    }];

    NSLog(@"test ended");
    XCTAssert(YES);

    CFRunLoopRun();
}

重要なのは次の3行です。

  • CFRunLoopRef rl = CFRunLoopGetCurrent();
  • CFRunLoopStop(rl);
  • CFRunLoopRun();

テスト関数を抜ける直前でCFRunLoopRun()でランループを起動させ待機し、非同期処理が完了したあとでCFRunLoopStopによりランループを停止させてテスト関数を抜けさせます。このときの引数にCFRunLoopGetCurrentで取っておいたCFRunLoopRefを渡したいので最初の一行があります。