4

키 - 값 관측이 광산에서 제대로 작동하는지 테스트하고 싶습니다. 그것에는 또 다른 속성에 의존하는 하나의 속성이 있습니다. 그들은과 같이 설정되어 있습니다 :OCMock으로 KVO 조롱

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

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

내가 firstProperty 변경, secondProperty에 바인딩 된 객체가 통지를 얻을 때 확인하는 단위 테스트를 실행합니다. 처음에는 +[OCMockObject observerMock]을 사용할 수있을 것이라고 생각했으나 NSNotificationCenter과 만 사용할 수 있습니다. 이것을 테스트하는 가장 좋은 방법은 무엇입니까?

답변

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 클래스 개체가 전달됩니다.

다음 코드를 추가하여 응답을 모의하려고 시도했지만 YESNO 값은 모두 스택의 NSKeyValueWillChange 예외와 함께 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"]; 
2

확인할 수있는 알림을 수신하는 secondProperty의 결과가있는 경우 실제 개체에 설정하고 나중에 상태를 확인하면됩니다. 그게 불가능하면 KVO 콜백을 secondProperty의 부분 모형을 만들고 기대할 수 :

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]; 
1

누구에게나 관심이있는 사람 : 여기에 OCMock이없는 해결책이 있습니다.

단순히 단위 테스트 클래스의 테스트 속성으로 변경할 값을 바인딩합니다.

다음 예제에서는 pages 배열을 변경할 때 numberOfPages 속성을 업데이트하고 KVO 알림을 시작하겠습니다.

DocumentTests 클래스에 boundInteger 속성을 선언 :

@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"]; 
} 

작품의 벌금을 내게 :)