Я работал над этим некоторое время после того, как ответ @ 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
.
Я попытался добавить следующий код, чтобы смоделировать ответ, но значения YES
и NO
оба терпят неудачу с EXC_BAD_ACCESS
исключениями с NSKeyValueWillChange в стеке.
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"];