objective-c - 使用 OCMock 模拟 KVO

标签 objective-c cocoa unit-testing key-value-observing ocmock

我想测试 Key-Value-Observation 是否适用于我的一个类(class)。它有一个属性,而这个属性又依赖于另一个。它们的设置如下:

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

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

我想运行单元测试以验证当 firstProperty 更改时,绑定(bind)到 secondProperty 的对象会收到通知。起初我以为我可以使用+[OCMockObject observerMock],但看起来只能与NSNotificationCenter一起使用。对此进行测试的最佳方法是什么?

最佳答案

在@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: 调用 mock 对象没想到被传递给 NSKeyValueObservance 类对象。

我尝试添加以下代码来模拟响应,但是 YESNO 的值都因 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"];

关于objective-c - 使用 OCMock 模拟 KVO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9603362/

相关文章:

c# - 使用最小起订量的扩展方法的单元测试

c# - 为什么 Moq 抛出 "expected Invocation on the mock at least once"。在哪里设置一次,即使它被设置为空?

python - 如何模拟一个模块但不模拟其中的所有方法?

ios - 在 Kiwi 测试期间获得 BAD_EXCESS,

ios - 按顺序发送 100 个 HTTP 请求

iphone - 数据源和 TableView 的问题

iphone - 单元测试找不到核心数据模型文件

objective-c - 要在 objective-c 中使用 UTType 要包含什么 header ?

ios - Cocoapods安装错误-无法找到 pod 的规范

Cocoa 应用程序在停用时隐藏