什么时候需要将应用程序源包含在测试目标中? [英] When do app sources need to be included in test targets?

查看:33
本文介绍了什么时候需要将应用程序源包含在测试目标中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

#import #import "ViewController.h"@interface ViewControllerTests : XCTestCase@结尾@implementation ViewControllerTests- (void)testExample{//使用不在测试目标中的类.ViewController * viewController = [[ViewController alloc] init];XCTAssertNotNil(viewController, @"");}@结尾

ViewController.h 不是 测试目标的一部分,但它可以毫无问题地编译和运行测试.

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

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

<块引用>

架构 i386 的未定义符号:_OBJC_CLASS_$_ViewController",引用自:ViewControllerTests.o 中的 objc-class-ref

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

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

<块引用>

Class ViewController 都实现了[...]/iPhone Simulator/[...]/MyApp.app/MyApp 和[...]/Debug-iphonesimulator/LogicTests.octest/LogicTests.将使用两者之一.哪个是不确定的.

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

 [viewController isKindOfClass:[ViewController 类]];//= 否//`Class` 对象的内存地址不同.NSString * instanceClassString = NSStringFromClass([viewController class]);NSString * classString = NSStringFromClass([ViewController class]);[instanceClassString isEqualToString:classString];//= 是//实际的类名是相同的

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

<小时>

评论摘要

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

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

解决方案

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

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

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

现在 Xcode 似乎试图不区分两者,并且默认创建一个应用程序测试目标让我们了解您可能需要更改的所有内容,以将您的逻辑测试目标转变为单元测试目标.

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

  1. 在测试目标的构建设置中删除Bundle Loader"和Test Host"构建设置.稍后我们将让 Xcode 将这些添加回来
  2. 您需要从测试目标中删除应用程序中的所有 .m 文件.您可以通过选择所有 .m 文件并在 Xcode 文件检查器中删除测试目标来执行此操作,也可以使用测试目标的编译源构建阶段.
  3. 更改测试目标的框架搜索路径".对于 Xcode 5,它们应该是$(SDKROOT)/Developer/Library/Frameworks$(继承)$(DEVELOPER_FRAMEWORKS_DIR)按照这个顺序和没有额外的引号或反斜杠
  4. 转到测试目标构建设置的常规"窗格,然后从下拉菜单中选择目标.如果菜单已经指定了您的应用程序目标,您应该将其关闭再打开.这将使 Xcode 使用正确的值重新配置捆绑加载器和测试主机设置.
  5. 最后仔细检查您的应用程序的方案.在方案下拉列表中选择编辑方案.然后单击测试操作.确保您的测试目标在信息窗格的列表中,并确保选择了所有测试.

这些信息或多或少来自上面链接的文档,但我更新了 Xcode 5 的步骤.

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

如果您有静态库目标

因此,如果您有一个静态库目标,您有两个选择:1. 逻辑测试2. 主机应用程序中的应用程序测试

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

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

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 not part of the test target yet this compiles and runs the tests with no issues.

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.

However, on an older project, with exactly the same test and ViewController file, the build fails at the linker phase:

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.

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):

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:

  1. There is no difference in the linker output (the command starting with Ld).
  2. There is no difference in the target dependancies (there is 1 dependancy to the test target,which is the app)
  3. There is no difference in the linker settings.

解决方案

I spent some time figuring this out.

If you read this documentation you 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.

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 two and 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.

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.

  1. 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
  2. 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.
  3. 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
  4. 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.
  5. 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.

This information more or less comes from the above linked documentation, but I updated the steps for 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

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

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.

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.

这篇关于什么时候需要将应用程序源包含在测试目标中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆