ios 什么时候需要将应用程序源包含在测试目标中?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21911168/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When do app sources need to be included in test targets?
提问by Robert
In a new project I have this simple test
在一个新项目中,我有这个简单的测试
#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 is notpart of the test target yet this compiles and runs the tests with no issues.
ViewController.h不是测试目标的一部分,但它可以毫无问题地编译和运行测试。
I think this is because the application is built first (as a dependancy) then the tests. The linker then figures it out what the ViewController class is.
我认为这是因为应用程序是首先构建的(作为依赖)然后是测试。链接器然后找出 ViewController 类是什么。
However, on an older project, with exactly the same test and ViewController file, the build fails at the linker phase:
但是,在旧项目中,使用完全相同的测试和 ViewController 文件,构建在链接器阶段失败:
Undefined symbols for architecture i386: "_OBJC_CLASS_$_ViewController", referenced from: objc-class-ref in ViewControllerTests.o
Undefined symbols for architecture i386: "_OBJC_CLASS_$_ViewController", referenced from: objc-class-ref in ViewControllerTests.o
This linker error occurs even if when a fresh XCTest unit testing target is created.
即使创建了新的 XCTest 单元测试目标,也会发生此链接器错误。
To get around this instead, it is possible to include the sources in both the app and the test targets (tick both boxes in the image above). This causes build warnings for duplicate symbols, in the simulator's system log (open the simulator and press cmd-/ to see this):
为了解决这个问题,可以在应用程序和测试目标中都包含源(勾选上图中的两个框)。这会导致在模拟器的系统日志中生成重复符号的警告(打开模拟器并按 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.
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.
These warnings occasionally cause issues illustrated by the following example:
这些警告有时会导致以下示例所示的问题:
[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
So the question is what setting(s) in the older project are requiring application source files to be included in the test target?
所以问题是旧项目中的哪些设置要求将应用程序源文件包含在测试目标中?
Summary of comments
评论摘要
Between the working and the non-working project:
在工作和非工作项目之间:
- There is no difference in the linker output (the command starting with
Ld
). - There is no difference in the target dependancies (there is 1 dependancy to the test target,which is the app)
- There is no difference in the linker settings.
- 链接器输出(以 开头的命令
Ld
)没有区别。 - 目标依赖没有区别(对测试目标有1个依赖,即应用程序)
- 链接器设置没有区别。
采纳答案by Hymanslash
I spent some time figuring this out.
我花了一些时间弄清楚这一点。
If you read this documentationyou find that Xcode has two modes for running tests. Logic Tests and Application Tests. The difference is Logic tests build their own target with your Classes and symbols built right in. The resulting executable can be run in the simulator and reports test output back to Xcode. Application tests on the other hand build a dynamic library linking to your code which is injected into the app at runtime. This allows you to run tests in iPhone environment and test Xib loading and other things.
如果您阅读本文档,您会发现 Xcode 有两种运行测试的模式。逻辑测试和应用测试。不同之处在于逻辑测试使用内置的类和符号构建自己的目标。生成的可执行文件可以在模拟器中运行并将测试输出报告回 Xcode。另一方面,应用程序测试构建一个链接到您的代码的动态库,该库在运行时注入到应用程序中。这允许您在 iPhone 环境中运行测试并测试 Xib 加载和其他内容。
Because the symbols are missing from your test target when you unlink the source files it appears your older project seems to have a test target configured for logic tests, not Application (unit) tests.
因为当您取消链接源文件时,测试目标中缺少符号,所以您的旧项目似乎为逻辑测试配置了测试目标,而不是应用程序(单元)测试。
As these days Xcode seems to be trying not to distinguish between the twoand defaults to creating an Application Tests target lets walk through all the things you might have to change to turn your Logic Test Target into a unit test one.
现在 Xcode 似乎试图不区分这两者,并且默认创建一个 Application Tests 目标,让我们逐步了解您可能需要更改的所有内容,以将您的 Logic Test Target 转换为单元测试目标。
I'm also going to assume that you have an Application Target and not a static library target as the directions will be a little different.
我还将假设您有一个应用程序目标而不是静态库目标,因为方向会有所不同。
- In the build settings for your test target delete "Bundle Loader" and "Test Host" build settings. We will get Xcode to add these back later
- You need to remove all the .m files from your application from the test target. You can either do this by selecting all the .m files and removing the test target in the Xcode File inspector or you can use the compile sources build phase of the test target.
- Change the "Framework search paths" for your test target. For Xcode 5 they should be
$(SDKROOT)/Developer/Library/Frameworks $(inherited) $(DEVELOPER_FRAMEWORKS_DIR)
in that order and with no extra quotes or backslashes - Go to the General pane of your test target's build settings and select your target from the drop down menu. If the menu already specifies your application target you should toggle it off and on again. This will make Xcode reconfigure the Bundle loader and Test Host settings with the correct value.
- Finally double check your application's scheme. In the scheme drop down select edit scheme. Then click the test action. Make sure you test target is in the list on the info pane and make sure all the tests are selected.
- 在测试目标的构建设置中删除“Bundle Loader”和“Test Host”构建设置。稍后我们将让 Xcode 将这些添加回来
- 您需要从测试目标的应用程序中删除所有 .m 文件。您可以通过选择所有 .m 文件并在 Xcode 文件检查器中删除测试目标来执行此操作,也可以使用测试目标的编译源构建阶段。
- 更改测试目标的“框架搜索路径”。对于 Xcode 5,它们应该按
$(SDKROOT)/Developer/Library/Frameworks $(inherited) $(DEVELOPER_FRAMEWORKS_DIR)
该顺序排列,并且没有额外的引号或反斜杠 - 转到测试目标构建设置的常规窗格,然后从下拉菜单中选择目标。如果菜单已经指定了您的应用程序目标,您应该将其关闭再打开。这将使 Xcode 使用正确的值重新配置捆绑加载器和测试主机设置。
- 最后仔细检查您的应用程序的方案。在方案下拉列表中选择编辑方案。然后单击测试操作。确保您的测试目标在信息窗格的列表中,并确保选择了所有测试。
This information more or less comes from the above linked documentation, but I updated the steps for Xcode 5.
这些信息或多或少来自上面链接的文档,但我更新了 Xcode 5 的步骤。
EDIT:
编辑:
Hmm 100% note what eph515 is saying about debug symbols being visible but you might also want to check that someone didn't set your scheme's test action to build in the Release
or other configuration. Click the scheme selector an choose edit scheme. Click the test action and then make sure the Build Configuration is Debug
嗯 100% 请注意 eph515 关于调试符号可见的说法,但您可能还想检查是否有人没有将您的方案的测试操作设置为在Release
配置或其他配置中构建。单击方案选择器选择编辑方案。单击测试操作,然后确保构建配置为Debug
If you have a Static Library Target
如果您有静态库目标
So if you have a static library target you have two options: 1. Logic Tests 2. Application tests in a host app
因此,如果您有一个静态库目标,您有两个选择:1. 逻辑测试 2. 主机应用程序中的应用程序测试
For 1. you have to make sure that Bundle Loader
and Test Host
are empty for your static library target. Your sources then have to be compiled into the test target as they would have no other way to be run.
对于 1. 您必须确保静态库目标的Bundle Loader
和Test Host
为空。然后必须将您的源代码编译到测试目标中,因为它们没有其他方法可以运行。
For 2. You need to make a new app Project in Xcode and add your static Library project as a subproject. You then need to manually copy the Bundle Loader
and Test Host
build settings from your New App's test target to your Static Lib test target. Then you open the scheme for your new Test App and add your test target to the tests action for the new app.
To run the tests on your lib you run the test action for your host app.
对于 2. 您需要在 Xcode 中创建一个新的应用程序项目并将您的静态库项目添加为子项目。然后,您需要手动将新应用程序的测试目标中的Bundle Loader
和Test Host
构建设置复制到静态库测试目标。然后打开新测试应用程序的方案,并将测试目标添加到新应用程序的测试操作中。要在您的库上运行测试,您需要为您的主机应用程序运行测试操作。
回答by yood
On Xcode 6, I was able to fix this problem by checking "Allow testing Host Application APIs" in the test target > General > Testing.
在 Xcode 6 上,我能够通过在测试目标 > 常规 > 测试中选中“允许测试主机应用程序 API”来解决这个问题。
回答by eph515
I ran into this as well and followed Hymanslash's recommendation but with one more addition: Select your main target and looks for Symbols Hidden by Default (under Apple LVM 5.0 - Code Generation), if the value is Yes, change it to No. This seems to 'un hide' all the symbols of the compiled sources that the unit test target is looking for. Works for me. Please make sure that you include all the steps that Hymanslash outlined as well.
我也遇到了这个问题并遵循了 Hymanslash 的建议,但还有一个补充:选择您的主要目标并查找默认隐藏的符号(在 Apple LVM 5.0 - 代码生成下),如果值为 Yes,则将其更改为 No。这似乎“取消隐藏”单元测试目标正在寻找的编译源的所有符号。为我工作。请确保您还包括 Hymanslash 概述的所有步骤。
回答by Robert
The answer was a combination of Hymanslash's and eph515's answers.
答案是 Hymanslash 和 eph515 的答案的组合。
As in eph515's answer symbols hidden by default
should be No for debug.
在 eph515 中symbols hidden by default
,调试的答案应该是“否”。
Also deployment postprocessing
should be No for debug.
也deployment postprocessing
应该是 No 进行调试。
Also all libraries that are included in the test target should be removed from the unit test. All that should be left are the 3 in the screen shot plus anything that is specific to unit testing.
此外,应从单元测试中删除包含在测试目标中的所有库。剩下的就是屏幕截图中的 3 以及特定于单元测试的任何内容。
Also if there is a run build script build phase at the end of the list, then it should be removed (since it is an artefact of unit testing).
此外,如果列表末尾有运行构建脚本构建阶段,则应将其删除(因为它是单元测试的产物)。
Then do everything in Hymanslash's answer.
然后在Hymanslash's answer 中做所有事情。
回答by Luká? Mareda
In my case in Xcode 6.2 was error in different architectures in project target and tests target.
就我而言,Xcode 6.2 在项目目标和测试目标的不同架构中出错。
Project target has only armv7 and armv7s architectures (because of some older library)
项目目标只有 armv7 和 armv7s 架构(因为一些较旧的库)
Project Tests target has armv7, armv7s and arm64 architectures.
项目测试目标有 armv7、armv7s 和 arm64 架构。
Removing arm64 architecture solve this issue for my case.
对于我的案例,删除 arm64 架构解决了这个问题。
Project Editor -> Project Tests target -> Build Settings -> Valid Architectures = armv7 armv7s
(perhaps it is needed also to set "Architectures" instead of $(ARCHS_STANDARD) to $(ARCHS_STANDARD_32_BIT))
(也许还需要将“Architectures”而不是 $(ARCHS_STANDARD) 设置为 $(ARCHS_STANDARD_32_BIT))