我正在使用 XCTest 和 OCMock 2.2.1 进行单元测试。我有一个类,它使用以下方法获取包标识符:
NSString *bundleIdentifier = [[NSBundle bundleForClass:[self class]] bundleIdentifier];
在运行应用程序或此类的单元测试时,这将按预期工作。
在对其他类进行测试时,我部分地模拟了该对象,但仍然需要获取要运行的包标识符的方法。
我看到的是在将对象实例传递给 + [OCMockObjectpartialMockForObject:]
之前看起来正确:
(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
传递到 [OCMockObjectpartialMockForObject: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
的调用改变了它返回的内容。
除了模拟 MyObject 内部的调用之外,我还能做些什么来确保 bundleForClass
继续返回原始值吗?令人担忧的是,任何其他需要在另一个单元测试中部分模拟 MyObject 的人都需要记住提供 bundleForClass
的 stub 实现。
我目前的解决方案是请求包标识符并检查结果。如果它为零,我将调用 [NSBundle allBundles] 并迭代它们,直到找到一个具有非零的bundleIdentifier。虽然目前...有效...它 A) 不是很健壮 B) 非常暴力,C) 修改应用程序代码以支持单元测试。
还有其他人遇到过这个问题并提出更好的解决方案吗?
最佳答案
运行时运行正常。模拟对象是 NSProxy 的子类,因此是对象的 isa
之间的运行时绑定(bind)。并且该包被有效地破坏(特别是,isa
指向 Class
,然后通过 dyld
API 查找它以确定从中加载的 mach-o 镜像,并且 用于查找 bundle )。
OCMockObject
上可能有 API代理(或子类 OCPartialMockObject
),允许您检索原始类。当然,您必须使用它,这意味着您将通过仅应在测试中使用的模拟调用来污染您的代码。
或者,在您的包/框架/任何返回该类包的类中实现一个类方法。这不应该被 mock 。
关于objective-c - 调用 + [NSBundle bundleForClass :] on a partially mocked object is returning a different result than the unmocked object?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19030194/