当使用 RKMappingTest
对 RestKit 映射代码执行单元测试时,它们会失败并出现以下异常:
映射操作失败:给定 nil 目标对象,无法实例化映射的目标对象。
或(当目标对象被传递到 RKMappingTest
时):
映射操作未在给定对象表示中找到属性和关系映射的任何可映射值
RestKit 使用以下 Podfile 通过 Cocoapods 安装:
target :MyTarget do
pod 'RestKit'
end
target :MyTargetTests do
pod 'RestKit/Testing'
pod 'RestKit/Search'
end
要测试的 RKMapping 在常规应用程序包中创建,并在使用 lldb 调试器的 po
命令时正确显示。
当生成 RKEntityMapping 的方法被复制粘贴到单元测试类并在那里执行时,一切正常。
备注:
虽然我确实回答了我自己的问题,希望它对遇到同样问题的其他人有用,但我鼓励任何能提出更好解决方案的人发布它。
最佳答案
发生这种情况的原因:
Disclaimer:
I am no expert on static libraries, linking and related dependencies. If I got something wrong about the way that linking or Cocoapods work, please correct me.
为此Podfile
, Cocoapods 构建了两个静态库——每个目标一个。
项目编译时,MyTarget
中的所有代码将链接到 LibPods-MyTarget.a
库和 MyTargetTests
中的所有代码将链接到 LibPods-MyTargetTests.a
图书馆。
它们都包含 RestKit/ObjectMapping
的副本组件(因为它是 RestKit
和 RestKit/Testing
的依赖项)。
生成 RKMapping
时在应用程序源 (MyTarget) 中,来自 LibPods-MyTarget.a
的类实现被使用了。
当在单元测试类中使用该映射时,RestKit 实现从其他库链接。
理论上,两个实现都包含相同的源代码,两个类具有相同的名称、相同的类号,甚至可能是底层 objc_class
结构包含相同的内容。
当您从测试类中调用方法时,它将按预期执行(实现来自应用程序库)。 说:根据分配初始化对象的位置,相同的源代码将从不同内存位置的不同副本加载。
但是,由于 Objective-C Class
构造比底层更高级别objc_class
结构,它们并不相同。
这意味着什么的例子:
假设我们有一个名为 MyObject
的类,其中包括具有以下签名的方法:
+ (RKObjectMapping*)generateMapping;
虽然方法本身工作得很好,但这个测试会失败:
- (void)testClassEquality {
RKEntityMapping *mappingFromAppBundle = [MyObject generateMapping];
Class testBundleMappingClass = [RKMapping class];
XCTAssert([mappingFromAppBundle isMemberOfClass:testBundleMappingClass],
@"Mapping class from app bundle doesn't match Mapping class from test bundle");
}
因为:
[RKMapping class]
来自 LibPods-MyTarget.a
!=
[RKMapping class]
来自 LibPods-MyTargetTests.a
RestKit 严重依赖 isMemberOfClass:
和 isSubclassOf:
实现其功能的操作。因此,这种重复的实现破坏了它。
解决方案:
快速而肮脏:
不要为两个目标使用两种不同的 Cocoapod 配置。使用简单的 Podfile,例如:
pod 'RestKit'
pod 'RestKit/Testing'
pod 'RestKit/Search'
然后对两个目标使用相同的库/配置。针对两个目标的相同副本的链接器链接。
死代码剥离应该防止不需要的代码包含在您的最终应用程序中。
但是:它仍然需要在每次构建时编译,如果你有 -ObjC
或 -all_load
设置了链接器标志,未使用的代码将随您的应用一起发布。
更脏:
I strongly advise against this, since it pretty much defeats the purpose of a unit test. I've seen this as another workaround and included it for the sake of completion:
将代码的实现复制并粘贴到单元测试类中,然后从那里使用它。
建议:
Cocoapods 首先为每个单独的组件创建一个静态库,然后将它们组合成一个更大的库,用于每个目标、项目或工作区。
应该可以在不使用大联合的情况下将小型库直接链接到目标中。通过这样做,在没有自动化的情况下,人们会杀死自动依赖管理,而 Cocoapods 正是为此而构建的。
如果有人有空并为此实现脚本或修改 Cocoapods 以添加功能,请告诉我。
其他解决方案?
如果我遗漏了 Cocoapods 已有的功能,或者您知道任何其他解决方案,请发表评论或将其发布为另一个答案。
关于ios - RestKit 和 Cocoapods : Mapping operation failed/did not find any mappable values,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23860482/