I worked on this for a while after @chrispix's answer inspired me to work in a different direction. I started with this:
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];
When I ran this test code, I got the following message:
OCMockObject[NSObject]: unexpected method invoked: isKindOfClass:<??>
expected: observeValueForKeyPath:@"firstProperty" ofObject:
I did some investigation and found that the -isKindOfClass:
call the mock object didn't expect was being passed an NSKeyValueObservance
class object.
I tried adding the following code to mock a response, but values of YES
and NO
both fail with EXC_BAD_ACCESS
exceptions with NSKeyValueWillChange in the stack.
BOOL returnVal = NO;
[[[secondPropertyObserver stub] andReturnValue:OCMOCK_VALUE(returnVal)] isKindOfClass:[OCMArg any]];
I stepped more carefully and found that my code wasn't causing this exception - it was while the autoreleasepool
was being drained. It then dawned on me that I needed to remove the observer. Below is the complete solution, including removing the observer.
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"];