在部分模拟对象上调用+ [NSBundle bundleForClass:]返回的结果与unmocked对象不同?

时间:2013-09-26 13:52:00

标签: objective-c ocmock

我正在使用XCTest和OCMock 2.2.1进行单元测试。我有一个类使用以下方法获取包标识符:

NSString *bundleIdentifier = [[NSBundle bundleForClass:[self class]] bundleIdentifier];

在运行应用程序或特别是此类的单元测试时,这可以正常工作。

在对其他类进行测试时,我正在部分模拟此对象,但仍需要获取包标识符的方法。

我所看到的是在将对象实例传递给+ [OCMockObject partialMockForObject:]之前看起来是正确的:

(lldb) po myObject
<MyObject: 0x1006ec480>
(lldb) po [NSBundle bundleForClass:[myObject class]]
NSBundle </Users/paynerc/Library/Developer/Xcode/DerivedData/xxxx/Build/Products/Debug/MyTests Tests.xctest> (loaded)
(lldb) po [[NSBundle bundleForClass:[myObject class]] bundleIdentifier]
com.paynerc.MyBundle

然而,在我将myObject传递给[OCMockObject partialMockForObject:myObject]之后,情况发生了变化:

(lldb) po myObject
<MyObject-0x1006ec480-401894396.880136: 0x1006ec480>
(lldb) po [NSBundle bundleForClass:[myObject class]]
NSBundle </Applications/Xcode.app/Contents/Developer/usr/bin> (loaded)
(lldb) po [[NSBundle bundleForClass:[myObject class]] bundleIdentifier]
nil

对象被修改并包含部分模拟魔法的事实是有道理的。似乎没有意义的是为什么对bundleForClass的调用改变了它返回的内容。

我能做些什么来确保bundleForClass继续返回原始值,而不是模仿MyObject中的调用?关注的是,在另一个单元测试中需要部分模拟MyObject的其他人需要记住提供bundleForClass的存根实现。

我目前的解决方案是请求捆绑标识符并检查结果。如果它是nil,我调用[NSBundle allBundles]并迭代它们,直到找到一个具有非零bundleIdentifier的那个。虽然目前...... 正常工作 ...它是A)不是非常强大B)可怕的暴力 - 以及C)修改应用程序代码以支持单元测试。

有没有其他人遇到过这个并提出更好的解决方案?

1 个答案:

答案 0 :(得分:3)

运行时运行正常。模拟对象是NSProxy的子类,因此,对象的isa与包之间的运行时绑定被有效地破坏(特别是isa指向Class然后通过dyld API查找,以确定从中加载的mach-o图像, 用于查找包。)

OCMockObject代理(或子类OCPartialMockObject)上可能存在允许您检索原始类的API。您必须使用那些,当然,这意味着您将使用仅应在测试中使用的模拟调用来污染您的代码。

或者,在bundle / framework中的一个类上实现一个类方法,或者返回类的包。那不应该被嘲笑。