Xcode:testing与DEBUG预处理器macros
当使用unit testing创build一个新项目时,Xcode将testingscheme的构buildconfiguration设置为Debug(与Runscheme相同)。
我应该区分Run(Command-R)和Test(Command-U)scheme吗?
也就是说,我是否应该创build一个名为Test的新的构buildconfiguration,在其中添加一个预处理器macrosTEST = 1,并将其用作Testscheme的构buildconfiguration? 或者,我应该保持运行和testing都debugging?
我来自一个Ruby / Rails的背景,通常有testing,开发和生产环境。 在我看来,debugging就像开发和发布就像生产,但我们错过了一个testing,这就是为什么我认为它可能是有道理的添加testing。
注释? 意见? build议?
我特别要求这个,因为我想编译一些testing用:
#ifdef TEST // Do something when I test. #endif
我不认为这很重要,如果我也编译这个debugging。 所以,我真的可以这样做:
#ifdef DEBUG // Do something when I run or test. #endif
但是,我真的只是打算现在做testing。 所以,这就是为什么我想我应该区分debugging和testing,但我想知道为什么Xcode默认情况下不会这样做? 苹果是否认为你不应该区分它们?
你可能会考虑添加一个新的构buildconfiguration。
在xcode 4中,点击左侧导航器上的项目。
在主窗口中,点击您的项目,然后select“信息”选项卡。
点击“+”button添加一个新的configuration(你可以打电话给你“testing”,如果你喜欢)。
现在,点击您的目标,然后转到构build设置选项卡。
search“预处理器macros”
在这里,你可以添加预处理器macros来为你的新的构buildconfiguration。
只需双击新的“testing”configuration,并添加TESTING = 1。
最后,编辑你的构buildscheme。 为您的schemeselecttesting选项。 应该有一个“构buildconfiguration”下拉菜单。 select你的“testing”configuration。
预处理器macros将不起作用,您需要在运行时检查环境。
static BOOL isRunningTests(void) { NSDictionary* environment = [[NSProcessInfo processInfo] environment]; return (environment[@"XCInjectBundleInto"] != nil); }
(更新了Xcode 7.3)
我不是创build一个testing版本configuration,而是:
-
创build了一个
Tests-Prefix.pch
文件:#define TEST 1 #import <SenTestingKit/SenTestingKit.h> #import "CocoaPlant-Prefix.pch"
-
在“testing”目标的构build设置的“前缀头”字段中inputpath。
-
将以下代码添加到
MyApp-Prefix.pch
导入的名为MyAppDefines.h
的文件的顶部:#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]
并且在运行testing时也可以工作。
在Tests-Prefix.pch
导入SenTestingKit也可以加快SenTestingKit Framework的编译速度,并允许我从所有testing文件的顶部删除#import <SenTestingKit/SenTestingKit.h>
。
我决定在代码本身中添加一个环境variables检查,而不是使用Robert提出的isRunningTests()build议。
- 编辑当前scheme(产品/scheme/编辑scheme)或Command + <
- 点击testingconfiguration
- 单击参数取消选中“使用运行操作的参数和环境variables”
- 展开环境variables部分并添加值为YES的variablesTESTING
- 添加到您的代码的地方,只要你需要:
+ (BOOL) isTesting { NSDictionary* environment = [[NSProcessInfo processInfo] environment]; return [environment objectForKey:@"TESTING"] != nil; }
完成后,屏幕应该看起来像这样。
上面的代码将在testing模式或应用程序模式下运行时findTESTING环境variables。 这段代码进入你的应用程序,而不是unit testing文件。 您可以使用
#ifdef DEBUG ... #endif
防止代码在生产中执行。
我testing了这么久,结果发现:
不仅可以将preproessormacros添加到您的unit testing目标(您可以有许多方法只使用variables进行unit testing ,并遵循@MattDiPasquale方法),
还必须在testing目标中添加条件complie文件。 我们应该重新编译这个文件,因为这个文件有一个新的预处理器macros,但是当你的预处理器macros没有设置的时候,这个文件已经构build在应用程序目标中。
希望这对你有所帮助。
Robert在SWIFT 3.0中的回答:
func isRunningTests() -> Bool { let environment = ProcessInfo().environment return (environment["XCInjectBundleInto"] != nil); }
查看环境variables以查看unit testing是否正在运行。 与罗伯特的答案类似,但我只为performance检查一次。
+ (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; }
在iOS上,unit testing运行时, [UIApplication sharedApplication]
将返回nil
。
Kev的答案在Xcode 8.3.2上适用于我的修改版本
+(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; }