24

OCUnitを使用して、デリゲートプロトコルをテストする方法はありますか?

私はこれを試していますが、うまくいきません。

-(void) testSomeObjDelegate {
  SomeObj obj = [[SomeObj alloc] initWithDelegate:self];
  [obj executeMethod];
}
-(void) someObjDelegateMethod {
  //test something here
}

別のスレッドでメソッドを呼び出してobj、デリゲートが呼び出されるまでテストをスリープ状態にしてみます。これをテストするもっと簡単な方法があるはずです。

4

2 に答える 2

53

デリゲートのテストは簡単です。コールバック メソッドのテストで ivar を設定し、デリゲート コールバックをトリガーする必要がある後に確認します。

たとえば、Somethingプロトコルのデリゲートを使用し、メッセージに応答しSomethingDelegateてそのデリゲートを送信するクラスがある場合、次のように-something:delegateInvoked:テストできます。

@interface TestSomeBehavior : SenTestCase <SomethingDelegate>
{
    Something *_object;
    BOOL _callbackInvoked;
}
@end

@implementation TestSomeBehavior

- (void)setUp {
    [super setUp];
    _object = [[Something alloc] init];
    _object.delegate = self;
}

- (void)tearDown {
    _object.delegate = nil;
    [_object release];
    [super tearDown];
}

- (void)testSomeBehaviorCallingBack {
    [_object doSomethingThatShouldCallBack];

    STAssertTrue(_callbackInvoked,
                 @"Delegate should send -something:delegateInvoked:");
}

- (void)something:(Something *)something delegateInvoked:(BOOL)invoked {
    _callbackInvoked = YES;
}

@end

ただし、質問の表現方法から、これはすでに理解していると思います。(私は主に他の読者のためにこれを投稿しています。)あなたは実際にはもっと微妙な質問をしていると思います:ランループをスピンする何かなど、後で発生する可能性のあるものをテストするにはどうすればよいですか。私の合図は、睡眠とスレッド化についてのあなたの言及です。

まず、別のスレッドで勝手にメソッドを呼び出すべきではありません。そのように使用しても安全であることが文書化されている場合にのみ、そうする必要があります。その理由は、クラスの内部が何をするかわからないからです。たとえば、実行ループでイベントをスケジュールする場合があります。この場合、別のスレッドでメソッドを実行すると、別の実行ループでイベントが発生します。これにより、クラスの内部状態が台無しになります。

少し時間がかかる可能性のある何かをテストする必要がある場合は、現在の実行ループを実行するだけでこれを行うことができます。これを行うために、上記の個々のテスト メソッドをどのように書き直すかを次に示します。

- (void)testSomeBehaviorCallingBack {
    NSDate *fiveSecondsFromNow = [NSDate dateWithTimeIntervalSinceNow:5.0];

    [_object doSomethingThatShouldCallBack];

    [[NSRunLoop currentRunLoop] runUntilDate:fiveSecondsFromNow];

    STAssertTrue(_callbackInvoked,
                 @"Delegate should send -something:delegateInvoked:");
}

-doSomethingThatShouldCallBackこれにより、現在の実行ループがデフォルト モードで 5 秒間スピンされます。これは、デフォルト モードでメインの実行ループでの作業がスケジュールされることを前提としています。このように動作する API では、使用する実行ループと実行するモードを指定できることが多いため、これは通常は問題ありません-[NSRunLoop runMode:beforeDate:]。期待している作業が行われる可能性が高くなります。

于 2009-07-09T07:32:23.953 に答える
12

Unit Testing Asynchronous Network Accessを確認してください。私はあなたを助けることができると思います。要するに、それは次のとおりです。

単体テスト コードとテスト対象の非同期コードの間の同期を処理する次のメソッドを追加します。

- (BOOL)waitForCompletion:(NSTimeInterval)timeoutSecs {
    NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutSecs];

    do {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeoutDate];
        if([timeoutDate timeIntervalSinceNow] < 0.0)
            break;
    } while (!done);

    return done;
}
于 2012-02-13T11:39:43.553 に答える