LoginSignup
34
33

More than 5 years have passed since last update.

Kiwi で非同期テストを行う

Last updated at Posted at 2013-03-19

最近 Kiwiで TDD やってます。Objective-C のテストってすごく書きづらいイメージでしたが、Kiwi はかなり使いやすくてお勧めです。

非同期メソッドを呼んで、そのメソッド内で変更された値をチェックするといったことも簡単にできます。

test.m
describe(@"SimpleRemoteObject", ^{
    context(@"read remote post object using POST", ^{
        beforeAll(^{
            [SRRemoteConfig defaultConfig].baseurl = @"http://localhost:2000/";
        });

        it(@"should get object using POST method", ^{
            NSDictionary *params = @{@"key":@"value"};
            __block NSArray *ret;
            [PostObj postAsyncWithParams:params async:^(NSArray *allRemote, NSError *error){
                ret = allRemote;
            }];
            [[expectFutureValue(ret) shouldEventually] beNonNil];
            [[expectFutureValue(ret) shouldEventually] haveCountOf:1];
            [[expectFutureValue(((PostObj *)[ret objectAtIndex:0]).key) shouldEventually] equal:@"value"];
        });
    });
});

上記は先日公開したライブラリ、SimpleRemoteObjectで使っている実際のテストケースですが、
PostObj:postAsyncWithParams:async: というメソッドは、SimpleRemoteObject がサーバからデータを取ってきて自分のインスタンスを作成、プロパティに値をマッピングして返すメソッドです。データ取得後に async で渡したブロックの中身が評価されます。

サーバはRequestの内容を echo しているだけなので、key プロパティに "value" が入っていればテストが成功するはずです。

このような場合、ブロックの中でセットされている ret をいきなり [[ret should] beNonNil]; などとしてしまうと、この式の評価の時点で値が入っていないのでテストは失敗します。
そこで、expectFutureValue()shouldEventually を組み合わせて、[[expectFutureValue(ret) shouldEventually] beNonNil];としてやることで、評価を遅延実行してくれます。
解説ページによると、単純に1秒待ってテストするようです。

処理がもっと長く掛かる場合は、shouldEventually の代わりに shouldEventuallyBeforeTimingOutAfter() を使います。
また、「2秒経ったらタイムアウトすること」みたいなテストも以下のように書けます。

test.m
SPEC_BEGIN(PropertyUtil)

describe(@"SimpleRemoteObject", ^{
    context(@"read timeout", ^{
        beforeAll(^{
            [SRRemoteConfig defaultConfig].baseurl = @"http://localhost:2000/";
            [SRRemoteConfig defaultConfig].timeout = 2;
        });

        it(@"should timeout with specified second", ^{
            __block NSError *ret;
            [TimeoutObj fetchAsync:^(NSArray *allRemote, NSError *error) {
                ret = error;
            }];
            [[expectFutureValue(ret) shouldEventuallyBeforeTimingOutAfter(3.0)] beNonNil];
            [[expectFutureValue(ret.localizedDescription) shouldEventuallyBeforeTimingOutAfter(3.0)] equal:@"The request timed out."];
        });
    });
});

SPEC_END

上記だと2秒でタイムアウトを行うようにしているのですが、shouldEventuallyBeforeTimingOutAfter(3.0)を使うことで、3秒間待ってから評価を実行しています。こうすることによって、確実にタイムアウトが発生するようにしているというわけです。

34
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
33