最近 Kiwiで TDD やってます。Objective-C のテストってすごく書きづらいイメージでしたが、Kiwi はかなり使いやすくてお勧めです。
非同期メソッドを呼んで、そのメソッド内で変更された値をチェックするといったことも簡単にできます。
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秒経ったらタイムアウトすること」みたいなテストも以下のように書けます。
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秒間待ってから評価を実行しています。こうすることによって、確実にタイムアウトが発生するようにしているというわけです。