OHHTTPStubsを使って気軽にHTTP通信をスタブする


クライアントサーバーアプリ開発では、開発・デバッグ中に問題が発生した時に原因がクライアント側にあるのかサーバー側にあるのか両方の視点から特定していかなければいけない場面に遭遇します。OHHTTPStubsを使うと、手軽に(通信部分のコードに手を入れることなく!)HTTP通信のスタブを実現できて大変便利です。

OHHTTPStubsの基本

[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
    return (リクエストに対して偽のレスポンスを返すかどうか);
} withStubResponse:^OHHTTPStubsResponse*(NSURLRequest *request) {
    return (返すレスポンスの内容);
}];

基本的にはスタブしたいHTTP通信が行われる前の適当なタイミングでstubRequestsPassingTest:withStubResponse:というメソッドを実行するだけです。

アプリ内でHTTPリクエストが発生すると、一つ目のブロックが実行されます。このブロックがYESを返すかどうかで、そのリクエストがスタブされるかどうかが決定されます。特定のURL宛のリクエストのみスタブしたい場合は、下記の用に書けます。

^BOOL(NSURLRequest *request) {
    return [request.URL.absoluteString isEqualToString:@"http://example.com/api/foo"];
}

スタブした場合に返す内容は、次のブロックで指定します。

^OHHTTPStubsResponse*(NSURLRequest *request) {
    return [OHHTTPStubsResponse responseWithFile:@"response.json" contentType:@"text/json" responseTime:2.0];
}

レスポンスの内容は直接NSDataで指定することもできますが、外部ファイルから読み込ませるのが楽です。うれしい事に、レスポンスタイムも指定できます。これはテストがはかどりますね。

NSURL *url = [NSURL URLWithString:@"http://example.com/api/foo"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"%@", operation.responseString);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"%@", error.localizedDescription);
}];
[operation start];

この状態で例えばAFNetworkingを使ってHTTPリクエストを送ってみると、ちゃんとresponse.jsonの内容がレスポンスとして返ってきます!

[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
    return [request.URL.absoluteString isEqualToString:@"http://www.yahoo.co.jp/"];
} withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
    return [OHHTTPStubsResponse responseWithFile:@"yahoo.json" contentType:@"text/json" responseTime:0.0];
}];
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
    return [request.URL.absoluteString isEqualToString:@"http://www.google.co.jp/"];
} withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
    return [OHHTTPStubsResponse responseWithFile:@"google.json" contentType:@"text/json" responseTime:0.0];
}];

複数の条件でスタブすることもできます。素晴らしい。

OHHTTPStubsの良い所は、アプリケーション側の通信関連コードに手を入れる事なくスタブを実現できることです。FacebookのiOS SDKの開発にも使われているくらいなので、もはや品質には疑いがないでしょう…。

Kiwiとあわせて使うような場合はbeforeAllでスタブしてafterAllでremoveAllRequestHandlersを呼んでスタブ解除するのが良さそう。

describe(@"FooBar", ^{
    beforeAll(^{
        [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
            return YES;
        } withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
            return [OHHTTPStubsResponse responseWithFile:@"something.json" contentType:@"text/json" responseTime:0.0];
        }];
    });
    afterAll(^{
        [OHHTTPStubs removeAllRequestHandlers];
    });

インストール

CocoaPodsで提供されているので、CocoaPodsを使える場合はCocoaPodsでインストールするのが楽です。

pod "OHHTTPStubs"

注意点

Its code use a private API to build an NSHTTPURLResponse, which is not authorized by Apple in applications published on the AppStore. So you will probably only link it with your Unit Tests target, or inside some #if DEBUG/#endif portions of your code.

さて、このOHHTTPStubsですが機能を実現するためにプライベートAPIが使われているため、OHHTTPStubsのコードが含まれたバイナリをAppStoreにサブミットしようとするとリジェクトされてしまいます。

従って、OHHTTPStubsを使う場合はテスト用のターゲットのみでリンクするようにするなり、#if DEBUG / #endifで囲うなりして使う必要があります。

基本的にはテストを効率化させるためのツールですが、サーバーとクライアント同時並行で開発を進めなければ行けないときにも活躍します。テストターゲット以外で使う場合はリジェクトにだけ注意をして活用していきましょう。

参考


「OHHTTPStubsを使って気軽にHTTP通信をスタブする」への6件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です