2

我正在使用 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]并遍历它们,直到找到一个具有非 nil 的 bundleIdentifier。虽然目前......有效......它是A)不是很强大B)可怕的蛮力和C)修改应用程序代码以支持单元测试。

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

4

1 回答 1

3

运行时行为正确。模拟对象是 NSProxy 的子类,因此,对象isa和包之间的运行时绑定被有效地破坏(特别是isa指向Classwhich 的点,然后通过 API 查找dyld以确定它被加载的 mach-o 图像from 并且用于查找捆绑包)。

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

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

于 2013-09-26T15:20:03.213 回答