OCUnit で Notification をテストする

2011年8月19日金曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

通知(Notification)を配信(POST)するメソッドのテストコードを考える。

ポイントは次の2つ
(1) 意図したタイミングで通知が配信されたかどうか
(2) 配信された通知は意図したものだったか

たとえば addEntryWithInfo:tagName: というメソッドを呼び出すと LKQueueDidAddEntryNotification という通知が送られることをテストする場合を書いてみる。

テスト対象のメソッドの実装イメージはこんな感じ。
- (LKQueueEntry*)addEntryWithInfo:tagName:
{
     :
    [[NSNotificationCenter defaultCenter]
        postNotificationName:LKQueueDidAddEntryNotification
                     object:self];
}
処理の最後で LKQueueDidAddEntryNotification をポストしている。objectの引数に自身のインスタンスを渡している。これは通知を受け取った時に notification.object として参照できる。

次にこれをテストするコード。
- (void)testDidAddNotification
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(_didAdd:)
                                                 name:LKQueueDidAddEntryNotification
                                               object:self.queue];

    self.calledNotificationName = nil;
    [self.queue addEntryWithInfo:@"NOTIFY-TEST-1" tagName:nil];
    STAssertEqualObjects(self.calledNotificationName, LKQueueDidAddEntryNotification, nil); // (1)
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
自身を通知対象として _didAdd: メソッドを登録する。その後、addEntryWithInfo:tagName: を呼び出す。これで通知 LKQueueDidAddEntryNotificationが配信される。(1) はその結果の確認。_didAdd: が正しく呼ばれたら (NSString*)self.calledNotificationName に通知名が入っているのでそれを確認する。これでポイントで挙げた「(1) 意図したタイミングで通知が配信されたかどうか」がテストできる。_didAdd: が呼ばれていないと self.calledNotificationNa は nil となるので STAssertEqualsObjects() が失敗する。

次に _didAdd: の実装。
- (void)_didAdd:(NSNotification*)notification

{
    STAssertEqualObjects(notification.name, LKQueueDidAddEntryNotification, nil);
    STAssertEquals(notification.object, self.queue, nil);
    self.calledNotificationName = LKQueueDidAddEntryNotification;
}
ここではポイントで挙げた「(2) 配信された通知は意図したものだったか」を確認している。もし違う通知が届いていたら最初の STAssertEqualObjects() が失敗する。

なお通知は NSRunLoop によって管理されている。この為、通知が配信(POST)された後、通知が届くにはランループが一巡してからになる。ということはテストコードで addEntryWithInfo:tagName: を呼び出した直後の self.calledNotificationName のテストは失敗するはず(_didAdd: が呼ばれていないから)。この為、一旦ランループを一巡させる為に下記を挿入する必要がある。
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
が、実際には不要だった。動作順番を見ていると testDidAddNotification内で addEntryWithInfo:tagName呼び出し -> post LKQueueDidAddEntryNotification -> _didAdd: -> testDidAddNotificationへ復帰、という動きだった。理由は不明だが OCUnit が通知のテストを考慮してそんな作りにしているのだろうか..


関連情報



iphone - OCUnit testing NSNotification delivery - Stack Overflow
addObserver: に NSMutableArray を渡している。POST時にここへ通知が追加されるようなことが書いてあるが初耳。リファレンスには書いてないようだが。。

Responses

Leave a Response

人気の投稿(過去 30日間)