在执行带有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
使用以下Podfile通过Cocoapods安装RestKit:

target :MyTarget do
    pod 'RestKit'
end

target :MyTargetTests do
    pod 'RestKit/Testing'
    pod 'RestKit/Search'
end

要测试的RKMapping是在常规应用程序捆绑包中创建的,并且在使用lldb调试器的po命令时可以正确显示。
当将生成RKEntityMapping的方法复制粘贴到单元测试类中并在其中执行时,一切工作正常。

注意:
尽管我的确回答了我自己的问题,希望对其他有相同问题的人有用,但我还是鼓励任何能提出更好解决方案的人提出。

最佳答案

发生这种情况的原因:

免责声明:
我不是静态库,链接和相关依赖项方面的专家。如果我对链接或Cocoapods的工作方式有误,请纠正我。

对于此Podfile,Cocoapods构建了两个静态库–每个目标库一个。
编译项目时,MyTarget中的所有代码都将与LibPods-MyTarget.a库链接,而MyTargetTests中的所有代码都将与LibPods-MyTargetTests.a库链接。
它们都包含RestKit/ObjectMapping组件的副本(因为它是RestKitRestKit/Testing的依赖项)。
在应用程序源(MyTarget)中生成RKMapping时,将使用LibPods-MyTarget.a中的类实现。
在单元测试类中使用该映射时,RestKit实现是从另一个库链接的。
从理论上讲,两个实现都包含相同的源代码,两个类具有相同的名称,相同的类号,甚至可能底层的objc_class结构也包含相同的内容。
当您从测试类中对其调用方法时,该方法将按应有的方式执行(实现来自apps库)。
说:根据对象在哪里进行alloc初始化,将从不同的副本在不同的内存位置加载相等的源代码。
但是,由于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已有的功能,或者您知道其他解决方案,请发表评论或将其作为其他答案。

10-08 06:07