40

在使用单元测试创​​建新项目时,Xcode 将构建配置设置为测试方案的调试(运行方案相同)。

我应该区分运行(Command-R)和测试(Command-U)方案吗?

即,我是否应该创建一个名为 Test 的新构建配置,向其添加预处理器宏 TEST=1,并将其用作测试方案的构建配置?或者,我应该将 Run & Test 都保留为 Debug 吗?

我来自 Ruby/Rails 背景,您通常拥有测试、开发和生产环境。在我看来,Debug 就像开发,Release 就像生产,但是我们缺少一个测试,这就是为什么我认为添加 Test 可能是有意义的。

注释?意见?建议?

我特别问这个是因为我想为 Test 编译一些东西:

#ifdef TEST
// Do something when I test.
#endif

我认为如果我也为调试编译它并不重要。所以,我真的可以这样做:

#ifdef DEBUG
// Do something when I run or test.
#endif

但是,我现在真的只是打算做测试。所以,这就是为什么我认为我应该区分调试和测试,但想知道为什么 Xcode 默认不为你做这件事?Apple 是否认为您不应该区分它们?

4

11 回答 11

35

预处理器宏将不起作用,您需要在运行时检查环境。

目标-c

static BOOL isRunningTests(void)
{
    NSDictionary* environment = [[NSProcessInfo processInfo] environment];
    return (environment[@"XCTestConfigurationFilePath"] != nil);
}

迅速

var unitTesting : Bool 
{
    return ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil
}

(针对 Xcode 11 更新)

于 2014-01-15T14:53:41.957 回答
30

您可能会考虑添加新的构建配置。

在 xcode 4 中,单击左侧导航器上的项目。

在主窗口中,单击您的项目,然后选择“信息”选项卡。

单击“+”按钮添加新配置(如果您愿意,可以将您的配置称为“测试”)。

现在,单击您的目标,然后转到构建设置选项卡。

搜索“预处理器宏”

在这里,您可以为新的构建配置添加预处理器宏。

只需双击新的“测试”配置,然后添加 TESTING=1。

最后,编辑您的构建方案。为您的方案选择测试选项。应该有一个“构建配置”下拉菜单。选择您的“测试”配置。

于 2013-02-05T23:27:50.040 回答
25

我没有创建测试构建配置,而是:

  1. 创建了一个Tests-Prefix.pch文件:

    #define TEST 1
    #import <SenTestingKit/SenTestingKit.h>
    #import "CocoaPlant-Prefix.pch"
    
  2. 在 Tests 目标的构建设置的 Prefix Header 字段中输入其路径。

  3. 将以下代码添加到我创建的名为 的文件的顶部MyAppDefines.h,导入MyApp-Prefix.pch

    #ifdef TEST
    #define TEST_CLASS NSClassFromString(@"AppDelegateTests") // any test class
    #define BUNDLE [NSBundle bundleForClass:TEST_CLASS]
    #define APP_NAME @"Tests"
    #else
    #define BUNDLE [NSBundle mainBundle]
    #define APP_NAME [[BUNDLE infoDictionary] objectForKey:(NSString *)kCFBundleNameKey]
    #endif
    

这使我可以BUNDLE在我所指的任何地方使用[NSBundle mainBundle]它,并且在我运行测试时也可以使用它。

导入 SenTestingKitTests-Prefix.pch还加快了 SenTestingKit 框架的编译,并允许我#import <SenTestingKit/SenTestingKit.h>从所有测试文件的顶部省略。

于 2011-07-20T14:34:34.470 回答
16

我决定在代码本身中添加对环境变量的检查,而不是使用罗伯特提出的 isRunningTests() 建议。

  1. 编辑当前方案(Product/Scheme/Edit Scheme)或Command+<
  2. 点击测试配置
  3. 单击参数取消选中“使用运行操作的参数和环境变量
  4. 展开环境变量部分并添加值为 YES 的变量 TESTING
  5. 将此添加到您的代码中,并在您需要时调用:
 + (BOOL) isTesting
    {
        NSDictionary* environment = [[NSProcessInfo processInfo] environment];
        return [environment objectForKey:@"TESTING"] != nil;
    }

完成后屏幕应如下所示。

屏幕应该是这样的

上面的代码在测试模式或应用模式下运行时会找到 TESTING 环境变量。此代码位于您的应用程序中,而不是单元测试文件中。您可以使用

#ifdef DEBUG
...
#endif

防止代码在生产环境中执行。

于 2014-08-29T01:29:01.943 回答
6

如果您创建一个测试构建配置,然后将 Target 的“Other Swift Flags”属性设置为“-DTEST”,它将定义一个可以在您的 swift 代码中工作的 TEST 宏。确保在 App 目标的构建设置中设置它,以便可以在 App 的 Swift 代码中使用它。

DEBUG 和 TEST 的其他 Swift 标志设置

然后使用这个集合,你可以像这样测试你的代码:

func testMacro() {
   #if !TEST 
       // skipping over this block of code for unit tests
   #endif
}
于 2018-06-10T22:12:05.670 回答
5

罗伯特在 SWIFT 3.0 中的回答:

func isRunningTests() -> Bool {
    let environment = ProcessInfo().environment
    return (environment["XCInjectBundleInto"] != nil);
}
于 2017-04-02T11:00:55.347 回答
3

我测试了这么久,发现了一个结果:

不仅您将 preproessor 宏添加到您的单元测试目标中(您可以有许多 仅使用变量进行单元测试的方法,并遵循 @MattDiPasquale 方法),

而且您还必须在测试目标中添加条件编译文件。我们应该重新编译这个文件,因为你有一个新的预处理器宏用于这个文件,但是这个文件已经内置在你的预处理器宏没有设置的应用程序目标中。

希望这对您有所帮助。

于 2012-12-18T07:43:46.137 回答
2

针对 Xcode10 更新:

static let isRunningUnitTests: Bool = {
    let environment = ProcessInfo().environment
    return (environment["XCTestConfigurationFilePath"] != nil)
}()
于 2018-11-26T17:15:54.920 回答
0

Look at environment variables to see if unit tests are running. Similar to Robert's answer but I only check once for performance sake.

+ (BOOL)isRunningTests {
   static BOOL runningTests;
   static dispatch_once_t onceToken;

   // Only check once
   dispatch_once(&onceToken, ^{
      NSDictionary* environment = [[NSProcessInfo processInfo] environment];
      NSString* injectBundle = environment[@"XCInjectBundle"];
      NSString* pathExtension = [injectBundle pathExtension];
      runningTests = ([pathExtension isEqualToString:@"octest"] ||
                      [pathExtension isEqualToString:@"xctest"]);
   });
   return runningTests;
}
于 2014-11-06T20:01:20.877 回答
0

在 Xcode 8.3.2 上适用于我的 Kev 答案的修改版本

+(BOOL)isUnitTest {

    static BOOL runningTests;
    static dispatch_once_t onceToken;

    // Only check once
    dispatch_once(&onceToken, ^{
        NSDictionary* environment = [[NSProcessInfo processInfo] environment];
        if (environment[@"XCTestConfigurationFilePath"] != nil && ((NSString *)environment[@"XCTestConfigurationFilePath"]).length > 0) {
            runningTests = true;
        } else {
            runningTests = false;
        }
    });
    return runningTests;
}
于 2017-08-13T17:55:37.790 回答
0

在 iOS 上,[UIApplication sharedApplication]nil在单元测试运行时返回。

于 2015-11-18T18:45:09.350 回答