【问题标题】:When do app sources need to be included in test targets?何时需要将应用程序源包含在测试目标中?
【发布时间】:2014-03-21 14:16:05
【问题描述】:

在一个新项目中我有这个简单的测试

#import <XCTest/XCTest.h>
#import "ViewController.h"

@interface ViewControllerTests : XCTestCase
@end

@implementation ViewControllerTests

- (void)testExample
{ 
    // Using a class that is not in the test target.
    ViewController * viewController = [[ViewController alloc] init];
    XCTAssertNotNil(viewController, @"");
}

@end

ViewController.h 是 not 测试目标的一部分,但它编译并运行测试没有任何问题。

我认为这是因为首先构建应用程序(作为依赖项)然后是测试。然后链接器找出 ViewController 类是什么。

但是,在一个较旧的项目中,具有完全相同的测试和 ViewController 文件,构建在链接器阶段失败:

Undefined symbols for architecture i386:
"_OBJC_CLASS_$_ViewController", referenced from:
  objc-class-ref in ViewControllerTests.o

即使创建了新的 XCTest 单元测试目标,也会发生此链接器错误。

为了解决这个问题,可以在应用程序和测试目标中包含源(勾选上图中的两个框)。这会导致在模拟器的系统日志中出现重复符号的构建警告(打开模拟器并按 cmd-/ 来查看):

Class ViewController is implemented in both 
[...]/iPhone Simulator/ [...] /MyApp.app/MyApp and 
[...]/Debug-iphonesimulator/LogicTests.octest/LogicTests. 
One of the two will be used. Which one is undefined.

这些警告有时会导致以下示例所示的问题:

 [viewController isKindOfClass:[ViewController class]]; // = NO
 // Memory address of the `Class` objects are different.

 NSString * instanceClassString = NSStringFromClass([viewController class]);
 NSString * classString         = NSStringFromClass([ViewController class]);

 [instanceClassString isEqualToString:classString]; // = YES
 // The actual class names are identical

那么问题是旧项目中的哪些设置要求将应用程序源文件包含在测试目标中?


cmets 总结

工作项目和非工作项目之间:

  1. 链接器输出没有区别(以Ld开头的命令)。
  2. 目标依赖没有区别(测试目标有1个依赖,即应用)
  3. 链接器设置没有区别。

【问题讨论】:

  • 测试目标设置可能有问题。你能显示你的测试目标的设置吗?
  • @Sulthan - 感谢您的回复。每个目标大约有 200 个构建设置。你知道哪些可能是相关的吗?
  • 链接和依赖。分享一个有问题的示例项目将是最好的解决方案。
  • @Sulthan - 不幸的是我不能分享这个项目。我已经验证,即使我创建了一个新的 XCTest 目标,旧项目仍然会发生这种情况,所以我猜问题出在项目设置中。从工作到不工作的目标依赖项是相同的(一项是应用程序)。除了“其他链接器标志”是-framework XCTestObjC 之外,链接器设置是相同的。我纠正了这个差异,它仍然无法编译:(你还能想到别的吗?
  • 直接检查链接器输出(项目导航器中最右边的选项卡),link 步骤。检查传递给链接器的参数之间的差异。

标签: ios objective-c xcode unit-testing xctest


【解决方案1】:

我花了一些时间解决这个问题。

如果您阅读this documentation,您会发现 Xcode 有两种运行测试的模式。逻辑测试和应用测试。不同之处在于逻辑测试使用内置的类和符号构建自己的目标。生成的可执行文件可以在模拟器中运行并将测试输出报告回 Xcode。另一方面,应用程序测试构建了一个动态库,链接到您的代码,该代码在运行时注入到应用程序中。这允许您在 iPhone 环境中运行测试并测试 Xib 加载和其他内容。

因为当您取消链接源文件时测试目标中缺少符号,所以您的旧项目似乎有一个为逻辑测试配置的测试目标,而不是应用程序(单元)测试。

现在 Xcode 似乎是 trying not to distinguish between the two 并且默认创建一个应用程序测试目标,让我们逐步了解您可能需要更改的所有内容,以将您的逻辑测试目标转变为单元测试目标。

我还将假设您有一个应用程序目标而不是静态库目标,因为方向会有所不同。

  1. 在测试目标的构建设置中删除“Bundle Loader”和“Test Host”构建设置。稍后我们将让 Xcode 添加这些内容
  2. 您需要从测试目标中删除应用程序中的所有 .m 文件。您可以通过选择所有 .m 文件并在 Xcode 文件检查器中删除测试目标来执行此操作,也可以使用测试目标的编译源构建阶段。
  3. 更改测试目标的“框架搜索路径”。对于 Xcode 5,它们应该是 $(SDKROOT)/Developer/Library/Frameworks $(inherited) $(DEVELOPER_FRAMEWORKS_DIR) 在那个顺序和with no extra quotes or backslashes
  4. 转到测试目标的构建设置的常规窗格,然后从下拉菜单中选择您的目标。如果菜单已经指定了您的应用程序目标,您应该将其关闭然后再打开。这将使 Xcode 使用正确的值重新配置 Bundle loader 和 Test Host 设置。
  5. 最后仔细检查您的应用程序的方案。在方案下拉列表中选择编辑方案。然后单击测试操作。确保您的测试目标位于信息窗格的列表中,并确保选择了所有测试。

此信息或多或少来自上述链接文档,但我更新了 Xcode 5 的步骤。

编辑:

嗯 100% 请注意 eph515 关于调试符号可见的说法,但您可能还想检查是否有人没有将您的方案的测试操作设置为在 Release 或其他配置中构建。单击方案选择器并选择编辑方案。单击测试操作,然后确保构建配置为Debug

如果您有静态库目标

所以如果你有一个静态库目标,你有两个选择: 1. 逻辑测试 2. 宿主应用中的应用测试

对于 1. 你必须确保 Bundle LoaderTest Host 对于你的静态库目标是空的。然后必须将您的源代码编译到测试目标中,因为它们没有其他方式可以运行。

对于 2. 您需要在 Xcode 中创建一个新的应用程序项目并将您的静态库项目添加为子项目。然后,您需要手动将 Bundle LoaderTest Host 构建设置从新应用的测试目标复制到静态库测试目标。然后打开新测试应用程序的方案并将测试目标添加到新应用程序的测试操作中。 要在您的 lib 上运行测试,请为您的主机应用程序运行测试操作。

【讨论】:

  • 感谢您的回答,这看起来不错。明天再调查。
  • 我做了所有的步骤,但都失败了。我什至在现有工作区中创建了一个新的应用程序目标(它自动生成了一个新的应用程序测试目标),但它仍然失败。我验证了框架搜索路径并按照描述重新生成了捆绑加载器和测试主机。我现在的猜测是有一个继承的工作区设置正在搞乱它。
  • “我还假设你有一个应用程序目标而不是一个静态库目标,因为方向会有点不同。”你能告诉我在哪里可以找到静态库目标的说明吗?
  • 我会添加到我的答案中
  • 我接受了这个答案,但给予 eph515 答案的赏金。这是正确的答案,但 eph515 帮助我找到了我的具体问题。
【解决方案2】:

在 Xcode 6 上,我可以通过在测试目标 > 常规 > 测试中选中“允许测试主机应用程序 API”来解决此问题。

【讨论】:

  • 有趣 - 谢谢!这是一个旧的现有项目吗?是否默认为新项目选择此选项?
  • 这适用于在 Xcode 5 中创建的项目,稍后将在 Xcode 6 中添加测试目标。我不知道它是否默认为新项目选择。
  • 谢谢,这修复了我使用 Xcode 5 创建的应用程序项目。但是“主机应用程序”选择不适用于我的静态库仍然有“架构的未定义符号”错误(遵循 @jackslash 的说明等等)。还有更多的线索可以用 Xcode 6 修复静态库的测试吗?
  • @clance_911 还要确保单个对象预链接已关闭
【解决方案3】:

我也遇到了这个问题并遵循 jackslash 的建议,但还有一个补充:选择您的主要目标并查找默认隐藏的符号(在 Apple LVM 5.0 - 代码生成下),如果值为是,请将其更改为否. 这似乎“取消隐藏”了单元测试目标正在寻找的已编译源的所有符号。为我工作。请确保您也包含jackslash 列出的所有步骤。

【讨论】:

  • 请注意,“默认隐藏的符号”的 iOS 默认值似乎是 NO 用于Debug 构建和YES 用于Release。您的项目可能应该与默认值匹配
  • 如果与符号有关,还要检查“在复制期间剥离调试符号”,对于 DebugYES 对于 Release 也应该是 NO
  • 是的,我相信“较新”的 XCode 项目将 Symbols Hidden by Default 设置为 NO 进行调试,因为我认为 XCode 5 现在默认包含单元测试,或者选择包含单元的选项test 在 Xcode 4 中选择。对于由 XCode 4 和之前创建的项目,不包含单元测试,该值为 YES
  • 答案是将这个标志加上Deployment Postprocessing改为NO进行调试。我还不得不摆弄喜欢的库以避免重复。我给予了这个答案的赏金,因为否则我不会去完成所有的构建设置。
  • 这是我的正确答案,乍一看与问题中描述的相同。我去了主要目标的“构建设置”,在“Apple LLVM 6.1 - 代码生成”下将“默认隐藏的符号”设置为“否”。 @eph515 谢谢!
【解决方案4】:

答案是 jackslash 和 eph515 答案的组合。

在 eph515 的回答中,symbols hidden by default 对于调试应该是“否”。

对于调试,deployment postprocessing 也应该是 No。

还应从单元测试中删除包含在测试目标中的所有库。应该只剩下屏幕截图中的 3 以及特定于单元测试的任何内容。

此外,如果列表末尾有运行构建脚本构建阶段,则应将其删除(因为它是单元测试的产物)。

然后在jackslash's answer 中做所有事情。

【讨论】:

  • 总而言之,我认为这将是一个非常有用和建设性的 SO 问题,供将来参考:)
  • 感谢您的总结和集中,这很有效。
【解决方案5】:

在我的 Xcode 6.2 中,项目目标和测试目标的不同架构中出现错误。

项目目标只有 armv7 和 armv7s 架构(因为一些较旧的库)

项目测试目标具有 armv7、armv7s 和 arm64 架构。

删除 arm64 架构为我解决了这个问题。

Project Editor -> Project Tests target -> Build Settings -> Valid Architectures = armv7 armv7s

(也许还需要将“架构”而不是 $(ARCHS_STANDARD) 设置为 $(ARCHS_STANDARD_32_BIT))

【讨论】:

【解决方案6】:

对我来说,这只是没有为方案添加测试目标的情况。

对于应用程序目标,转到编辑方案,然后单击右侧的测试,然后使用底部的 + 按钮添加一个测试目标:

【讨论】:

    【解决方案7】:

    当您创建Unit Testing Bundle(单元测试目标)来测试应用程序时,您有两个选择

    1. 启用Allow testing Host Application APIs
    General -> Host  Application <app_name> -> >check< Allow testing Host Application APIs 
    
    • 构建缓慢
    1. 将每个应用程序的测试文件添加到Target Membership[About]
    • 您应该注意用于可测试类的类依赖项(也应该添加它们)

    当您编写测试并且没有一个选项未启用时,您可以获得

    Undefined symbol: nominal type descriptor for <class_name>
    Undefined symbol: type metadata accessor for <class_name>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      • 1970-01-01
      • 2012-09-10
      • 1970-01-01
      • 2014-04-29
      • 2012-09-27
      相关资源
      最近更新 更多