4

Key-Value-Observation が私のクラスで適切に機能していることをテストしたいと思います。別のプロパティに依存する 1 つのプロパティがあります。それらは次のように設定されています。

+ (NSSet *)keyPathsForValuesAffectingSecondProperty {
    return [NSSet setWithObjects:
            @"firstProperty",
            nil];
}

- (NSArray *)secondProperty {
    return [self.firstProperty array];
}

単体テストを実行して、firstProperty変更時にバインドされたオブジェクトsecondPropertyが通知を受け取ることを確認したいと考えています。最初は が使えるかと思ったのです+[OCMockObject observerMock]が、 でしか使えないようNSNotificationCenterです。これをテストする最良の方法は何ですか?

4

3 に答える 3

7

@chrispixの答えが私に別の方向に取り組むように促した後、私はしばらくこれに取り組みました. 私はこれから始めました:

id objectToObserve = [[TheClassBeingTested alloc] init];

id secondPropertyObserver = [OCMockObject mockForClass:[NSObject class]];
[[secondPropertyObserver expect] observeValueForKeyPath:@"secondProperty"
                                               ofObject:objectToObserve
                                                 change:OCMOCK_ANY
                                                context:[OCMArg anyPointer]];
[objectToObserve addObserver:secondPropertyObserver
                  forKeyPath:@"secondProperty"
                     options:NSKeyValueObservingOptionNew
                     context:NULL];

// Do something to modify objectToObserve's firstProperty    

[secondPropertyObserver verify];

このテスト コードを実行すると、次のメッセージが表示されました。

OCMockObject[NSObject]: unexpected method invoked: isKindOfClass:<??> 
    expected:     observeValueForKeyPath:@"firstProperty" ofObject:

調査を行ったところ、モック オブジェクトが予期していなかった呼び出しがクラス オブジェクト-isKindOfClass:に渡されていることがわかりました。NSKeyValueObservance

応答をモックするために次のコードを追加しようとしましたが、スタック内の NSKeyValueWillChange で例外が発生し、YESとの値がNO両方とも失敗します。EXC_BAD_ACCESS

BOOL returnVal = NO;
[[[secondPropertyObserver stub] andReturnValue:OCMOCK_VALUE(returnVal)] isKindOfClass:[OCMArg any]];

私はより慎重にステップを踏み、私のコードがこの例外を引き起こしていないことを発見しました.それはautoreleasepool. その後、オブザーバーを削除する必要があることに気づきました。以下は、オブザーバーの削除を含む完全なソリューションです。

id objectToObserve = [[TheClassBeingTested alloc] init];

id secondPropertyObserver = [OCMockObject mockForClass:[NSObject class]];

BOOL returnVal = NO;
[[[secondPropertyObserver stub] andReturnValue:OCMOCK_VALUE(returnVal)] isKindOfClass:[OCMArg any]];

[[secondPropertyObserver expect] observeValueForKeyPath:@"secondProperty"
                                               ofObject:objectToObserve
                                                 change:OCMOCK_ANY
                                                context:[OCMArg anyPointer]];

[objectToObserve addObserver:secondPropertyObserver
                  forKeyPath:@"secondProperty"
                     options:NSKeyValueObservingOptionNew
                     context:NULL];

// Do something to modify objectToObserve's firstProperty    

[secondPropertyObserver verify];

[objectToObserve removeObserver:secondPropertyObserver
                     forKeyPath:@"secondProperty"];
于 2012-03-08T13:24:54.480 に答える
2

確認できる通知の受信になんらかの結果がsecondPropertyある場合は、それを実際のオブジェクトに設定し、後で状態を検証します。それが不可能な場合は、部分的なモックを作成してsecondProperty、KVO コールバックを期待できます。

id observedObject = // ...initialize observed class
observedObject.secondProperty = // initialize secondProperty
id mockSecondProperty = [OCMockObject partialMockForObject:observedObject.secondProperty];
[[mockSecondProperty expect] observeValueForKeyPath:@"firstProperty" ofObject:observedObject change:OCMOCK_ANY context:OCMOCK_ANY];

observedObject.firstProperty = // modify firstProperty

[mockSecondProperty verify];
于 2012-03-07T18:06:02.657 に答える
1

これに興味がある人のために:これがOCMockなしの解決策です。

変更する予定の値を単体テストクラスのテストプロパティにバインドするだけです。

次の例では、プロパティを更新し、配列numberOfPagesを変更したときにKVO通知を発行する必要があります。pages

クラスでboundIntegerプロパティを宣言します。DocumentTests

@interface DocumentTests : SenTestCase 
@property (assign) int boundInteger;
@end

次に、次のようにテストケースを実装します。

- (void)testNumberOfPages
{
    Document *doc = [[Document alloc] init];

    [self bind:@"boundInteger" toObject:doc withKeyPath:@"numberOfPages" options:nil];

    doc.pages = arrayOfThreePagesIHaveBuildSomewhereElse;

    STAssertEquals(self.boundInteger, 3, @"Wrong number of pages.");
    STAssertEquals(doc.numberOfPages, 3, @"Wrong number of pages.");

    [self unbind:@"boundInteger"];
}

私にとってはうまくいきます:)

于 2012-07-27T09:38:00.233 に答える