Foo类在MyApp和MyAppTestCase中实现。将使用两者之一。哪一个未定义

时间:2011-05-27 08:27:45

标签: objective-c xcode cocoa macos

最近我开始对我的应用程序进行单元测试。这个项目(在Xcode4中)是在没有单元测试包的情况下创建的,所以我不得不进行设置。 我已按照此处的步骤操作:http://cocoawithlove.com/2009/12/sample-mac-application-with-complete.html 并且它适用于简单的类,但现在我正在尝试测试一个依赖于另一个和另一个类的类等。

首先我收到了一个链接器错误,所以我将*.m个文件添加到了测试用例目标中,但是现在我收到了我正在尝试测试的每个类的警告:

  

Class Foo在两个MyApp中实现   和MyAppTestCase。其中一个会   使用。哪一个未定义。

我想知道为什么会这样?我怎么解决这个问题?也许我在设置单元测试目标时遗漏了什么?

编辑 - 解决方案

  • 将“Bundle Loader”正确设置为$(BUILT_PRODUCTS_DIR)/AppName.app/AppName

  • 将“默认隐藏的符号”设置为(在目标应用程序的构建设置中)。这是链接器错误的来源,因为它默认为YES!我一直在努力奋斗这么久!。

来源:Linking error for unit testing with XCode 4?

6 个答案:

答案 0 :(得分:42)

  
    

Class Foo在MyApp和MyAppTestCase中实现。将使用两者之一。哪一个未定义。

  
     

我想知道为什么会这样?

因为两个图像(应用程序和单元测试包)都定义了类的实现。该类被动态加载到objc运行时。 objc运行时使用平面命名空间。这是如何工作的:

  • 加载二进制文件,从其依赖项开始
  • 在加载每个二进制文件时,objc类向objc运行时
  • 注册
  • 如果加载了两次具有特定名称的类,则行为未定义。可以将一个类(具有相同名称)的实现加载到objc运行时。
这里的典型问题是您将返回一个实现 - 当类型冲突时(当类不是来自同一源文件时),您的应用程序可能会崩溃。

您通常可以通过重命名类或在一个图像中导出类来避免这种情况。重命名该课程显然不适用于您的情况。你有一个文件Foo.m,当它应该在一个文件中时,它被两个图像编译,导出和加载。

这应该被解释为重复的符号链接器错误。即使实现是相同的源文件(并且实现是相同的) - 这是一个必须修复的问题。

  

我该如何解决这个问题?

如果Foo.m是应用程序的类,则必须从单元测试中删除(不编译和链接)Foo.m。如果它是单元测试的一部分,则不要编译并将其链接到单元测试目标。

然后,按照帖子中的说明将您的单元测试链接/加载到应用程序。它位于帖子的这个一般区域:其中“WhereIsMyMac”是您单元测试的应用程序的名称。这将使测试目标链接到应用程序(因此在编译时不会出现链接器错误)。重要的部分是您的测试文件是在单元测试目标(仅)中编译的,以及您的应用程序的类编译并链接到应用程序。你不能只是添加它们 - 它们动态地链接和加载。

  

也许我在设置单元测试目标时错过了什么?

来自你链接的文章:

  
    

注意:测试目标是一个单独的目标。这意味着您需要注意目标成员资格。应将所有应用程序源文件仅添加到应用程序目标。测试代码文件应仅添加到测试目标中。

  

你出错的部分可能是单元测试包的链接和加载阶段。

答案 1 :(得分:17)

如果您正在使用Cocoapods,则您的podfile只需要主要目标部分中的依赖项,而不是测试目标。如果您确实为测试目标添加了重复的依赖项,那么您将收到OP的错误消息。

target 'MyProject' do
pod 'Parse'

end

target 'MyProjectTests' do

end

target 'MyProjectUITests' do

end

答案 2 :(得分:12)

对我来说,我需要做的只是取消选中使Foo类成为单元测试目标成员的复选框。它不应该是两个目标的成员,应该如下所示:

Target Membership

如果您看不到图像,则会显示Xcode“目标成员资格”窗格的屏幕截图。有两个目标:一个带有“A”应用程序图标和测试名称。另一个是单元测试目标,并有一个单元测试图标:

Target Membership
[X] Foo
[ ] FooTests

答案 3 :(得分:3)

对我来说,这发生了,因为我已经部署到设备,然后在我启用NSZombies时模拟器。解决方案是切换到模拟器配置&做产品 - >清洁然后切换到设备配置&照着做。错误消失了。它与构建缓存有关。

答案 4 :(得分:2)

原因是您覆盖了在其他目标中定义的App Target的构建设置的k1

<强>解决方案:

  

转到您的应用目标并找到RUNPATH_SEARCH_PATHS构建设置并使用RUNPATH_SEARCH_PATHS标记:调试发布

答案 5 :(得分:0)

遇到相同的问题,我的情况是在/System/Library/Frameworks/Foundation.framework/Foundation中都实现了NSNotification类,是否有任何家伙遇到相同的问题,任何方向或建议都会得到应用。 / p>