什么时候应用程序源码需要包含在testing目标中?
在一个新的项目中,我有这个简单的testing
#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 不是testing目标的一部分,但它编译和运行testing没有问题。
我认为这是因为应用程序是首先(作为依赖),然后testing。 链接器然后找出ViewController类是什么。
但是,在一个较旧的项目中,使用完全相同的testing和ViewController文件,构build在链接器阶段失败:
Undefined symbols for architecture i386: "_OBJC_CLASS_$_ViewController", referenced from: objc-class-ref in ViewControllerTests.o
即使创build了新的XCTestunit testing目标,也会出现此链接器错误。
为了解决这个问题,可以在应用程序和testing目标中包含源代码(在上图中勾选两个框)。 这会在模拟器的系统日志中产生重复符号的构build警告(打开模拟器并按下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
所以问题是旧项目中的哪些设置需要将应用程序源文件包含在testing目标中?
评论摘要
在工作和非工作项目之间:
- 链接器输出(以
Ld
开头的命令)没有区别。 - 目标依赖关系没有区别(testing目标有1个依赖关系,即应用程序)
- 链接器设置没有区别。
我花了一些时间弄清楚这一点。
如果你阅读这个文档,你会发现Xcode有两种运行testing的模式。 逻辑testing和应用testing。 不同之处在于逻辑testing使用内置的类和符号构build自己的目标。生成的可执行文件可以在模拟器中运行,并将testing输出报告回Xcode。 另一方面,应用程序testing会build立一个链接到您的代码的dynamic库,在运行时将其注入到应用程序中。 这使您可以在iPhone环境中运行testing并testingXib加载和其他事情。
由于在解除链接源文件时,testing目标中缺less符号,因此旧项目似乎有一个为逻辑testingconfiguration的testing目标,而不是应用程序(单元)testing。
由于这些日子Xcode似乎试图不区分这两个和默认创build一个应用程序testing目标让我们走过所有的事情,你可能必须改变你的逻辑testing目标变成一个unit testing。
我也将假设你有一个应用程序目标,而不是一个静态库目标,因为方向会有所不同。
- 在testing目标的编译设置中,删除“Bundle Loader”和“Test Host”编译设置。 稍后我们会让Xcode添加这些
- 您需要从testing目标中删除应用程序中的所有.m文件。 您可以通过select所有.m文件并在Xcode文件检查器中删除testing目标来完成此操作,也可以使用testing目标的编译源代码生成阶段。
- 更改testing目标的“框架searchpath”。 对于Xcode 5,它们应该是
$(SDKROOT)/Developer/Library/Frameworks $(inherited) $(DEVELOPER_FRAMEWORKS_DIR)
,并且没有多余的引号或反斜杠 - 转到testing目标的构build设置的常规窗格,然后从下拉菜单中select您的目标。 如果菜单已经指定了您的应用程序目标,则应该将其closures再打开。 这将使Xcode使用正确的值重新configurationBundle加载器和testing主机设置。
- 最后仔细检查你的应用程序的scheme。 在scheme下拉select编辑scheme。 然后点击testing操作。 确保testing目标在信息窗格的列表中,并确保所有的testing都被选中。
这些信息或多或less来自上面的链接文档,但我更新了Xcode 5的步骤。
编辑:
嗯,100%注意到eph515所说的关于debugging符号是可见的,但是你也可能想要检查有人没有设置你的scheme的testing动作来构buildRelease
或其他configuration。 单击schemeselect器并select编辑scheme。 单击testing操作,然后确保生成configuration是Debug
如果你有一个静态库目标
所以如果你有一个静态库目标,你有两个select:1.逻辑testing2.应用程序testing在主机应用程序
对于1.你必须确保你的静态库目标的Bundle Loader
和Test Host
是空的。 然后你的源码必须被编译到testing目标中,因为它们没有其他方法可以运行。
对于2.您需要在Xcode中创build一个新的应用程序项目,并将您的静态库项目添加为子项目。 然后,您需要手动将Bundle Loader
和Test Host
构build设置从新应用程序的testing目标复制到您的Static Libtesting目标。 然后,您打开新testing应用程序的scheme,并将testing目标添加到新应用程序的testing操作中。 要在您的lib上运行testing,请为您的主机应用程序运行testing操作。
在Xcode 6上,我可以通过在testing目标>常规>testing中选中“允许testing主机应用程序API”来解决这个问题。
我也遇到了这个问题,并遵循了Jackslash的build议,但又添加了一个新的function:select你的主要目标并寻找默认的符号(在Apple LVM 5.0 – 代码生成下),如果值为Yes,则将其更改为No。以“隐藏”unit testing目标正在寻找的编译源的所有符号。 为我工作。 请确保您包括所有的步骤,以及所示的轮廓。
答案是jackslash和eph515的答案的组合。
正如在eph515的答案symbols hidden by default
应该是为了debugging。
另外deployment postprocessing
应该是否为debugging。
此外,所有包含在testing目标中的库都应该从unit testing中移除。 所有应该留下的是屏幕截图中的3以及任何特定于unit testing的内容。
另外,如果在列表末尾有一个运行构build脚本构build阶段,那么它应该被删除(因为它是unit testing的制造)。
然后, 千奇百怪的回答做一切事情。
在我的情况下在Xcode 6.2是在不同的架构在项目目标和testing目标的错误。
项目目标只有armv7和armv7s体系结构(由于一些较旧的库)
项目testing目标有armv7,armv7s和arm64体系结构。
去除arm64架构解决这个问题,我的情况。
Project Editor -> Project Tests target -> Build Settings -> Valid Architectures = armv7 armv7s
(也许还需要将“架构”而不是$(ARCHS_STANDARD)设置为$(ARCHS_STANDARD_32_BIT))
对我而言,这只是一个没有为计划jointesting目标的情况。
对于应用程序目标去编辑计划,然后单击右侧的testing,然后添加一个testing目标与底部的+button: