当使用RKMappingTest
对RestKit映射代码执行单元测试时,它们会失败,例如:
Mapping operation failed: Given nil destination object and unable to instantiate a destination object for mapping.
或(当目标对象传递到RKMappingTest
时):
Mapping operation did not find any mappable values for the attribute and relationship mappings in the given object representation
RestKit通过Cocoapods使用以下Podfile安装:
target :MyTarget do
pod 'RestKit'
end
target :MyTargetTests do
pod 'RestKit/Testing'
pod 'RestKit/Search'
end
要测试的RKMapping是在常规应用程序包中创建的,并且在使用lldb调试器的po
命令时可以正常运行。
当生成RKEntityMapping的方法被复制粘贴到单元测试类并在那里执行时,一切正常。
虽然我确实回答了我自己的问题,希望对其他有相同问题的人有用,但我鼓励任何能够提出更好解决方案的人发布。
答案 0 :(得分:2)
<子>声明:子>
我不是静态库,链接和相关依赖项的专家。如果我对链接或Cocoapods的工作方式有误,请纠正我。
对于这个Podfile
,Cocoapods构建了两个静态库 - 每个目标一个。
编译项目时,MyTarget
中的所有代码都会与LibPods-MyTarget.a
库相关联,MyTargetTests
中的所有代码都会链接到LibPods-MyTargetTests.a
库。
它们都包含RestKit/ObjectMapping
组件的副本(因为它是RestKit
和RestKit/Testing
的依赖关系。)
在应用程序源(MyTarget)中生成RKMapping
时,使用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
个链接器标记,那么未使用的代码将随您的应用程序一起提供。
我强烈建议不要这样做,因为它几乎违背了单元测试的目的。我已经将此视为另一种解决方法,并将其包含在内以便完成:
将代码的实现复制并粘贴到单元测试类中,然后从那里使用它。
Cocoapods首先为每个组件创建一个静态库,并将它们组合成一个更大的库,用于每个目标,项目或工作区。
应该可以将小型库直接链接到目标而不使用大型联合。通过这样做,没有自动化,人们就会杀死Cocoapods为其构建的自动依赖管理。
如果有人有时间并为此实现脚本或修改Cocoapods以添加功能,请告诉我。
如果我错过了Cocoapods已有的功能或您知道任何其他解决方案,请将其评论或发布为另一个答案。