Why does OCMock partialMock break KVO?

2019-06-24 12:52发布

If I have an object that uses KVO to observe a property on some object and then create a partial mock for that observer I no longer receive any notifications. Why is this?

Here's a minimal example:

@interface TestPartialMockAndKVO : SenTestCase
@end
@implementation TestPartialMockAndKVO

- (void)test {
    // Should print "Changed!" when foo property is changed
    MyObserver* myObserver = [[[MyObserver alloc] init] autorelease];

    // But with this line, there is no print out
    [OCMockObject partialMockForObject:myObserver];

    [myObserver setFoo:@"change"];
}

@end

-

@interface MyObserver : NSObject    
@property (copy) NSString* foo;
@end
@implementation MyObserver

- (id)init {
    self = [super init];
    [self addObserver:self forKeyPath:@"foo" options:0 context:NULL];
    return self;
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
    NSLog(@"Changed!");
}

- (void)dealloc { ... }    
@end

1条回答
太酷不给撩
2楼-- · 2019-06-24 13:34

Both KVO and OCMock are doing some little runtime tricks whereby they create a private subclass of your actual class in order to perform their magic. KVO is doing a thing called "isa-swizzling", and OCMock is creating an object to be the forwarding target of your original object.

Each system is sort of off in its own little world, with its own class that has nothing to do with the other. Mocking KVO with OCMock looks similar to your problem. I think you should be able to make this work just by telling your mock to

[[myMock expect] observeValueForKeyPath:@"foo"
                               ofObject:myObserver
                                 change:[OCMArg any]
                                context:[OCMArg any]];
查看更多
登录 后发表回答