使用单元测试创建新项目时,Xcode将构建配置设置为Debug的Test方案(与Run方案相同)。
我应该区分Run(Command-R)&测试(Command-U)方案?
即,我应该创建一个名为Test的新构建配置,为它添加预处理器宏TEST = 1,并将其用作测试方案的构建配置吗?或者,我应该保持Run&测试两者作为Debug?
我来自Ruby / Rails背景,您通常拥有测试,开发和生产环境。在我看来,Debug就像开发一样,Release就像生产一样,但我们错过了一个测试,这就是为什么我认为添加Test可能有意义。
评论?意见?建议?
我特意问这个,因为我想用Test编译一些东西:
#ifdef TEST
// Do something when I test.
#endif
如果我也为Debug编译它,我认为这不重要。所以,我真的可以做到:
#ifdef DEBUG
// Do something when I run or test.
#endif
但是,我现在真的只打算为测试做这件事。所以,这就是为什么我认为我应该区分debug&测试,但我想知道为什么Xcode默认不为你做那个? Apple认为你不应该区分它们吗?
答案 0 :(得分:28)
您可以考虑添加新的构建配置。
在xcode 4中,单击左侧导航器上的项目。
在主窗口中,单击您的项目,然后选择“信息”选项卡。
单击“+”按钮添加新配置(如果您愿意,可以将其称为“test”)。
现在,点击您的目标,然后转到构建设置标签。
搜索“预处理器宏”
在这里,您可以为新的构建配置添加预处理器宏。
只需双击新的“测试”配置,然后添加TESTING = 1。
最后,编辑您的构建方案。选择方案的测试选项。应该有一个“Build Configuration”下拉菜单。选择“测试”配置。
答案 1 :(得分:27)
预处理器宏不起作用,您需要在运行时检查环境。
static BOOL isRunningTests(void)
{
NSDictionary* environment = [[NSProcessInfo processInfo] environment];
return (environment[@"XCInjectBundleInto"] != nil);
}
(针对Xcode 7.3更新)
答案 2 :(得分:24)
而不是创建测试构建配置,我:
创建了一个Tests-Prefix.pch
文件:
#define TEST 1
#import <SenTestingKit/SenTestingKit.h>
#import "CocoaPlant-Prefix.pch"
在测试目标的构建设置的前缀标题字段中输入其路径。
将以下代码添加到我创建的名为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]
而不是Tests-Prefix.pch
,并且在运行测试时也可以使用它。
在#import <SenTestingKit/SenTestingKit.h>
中导入SenTestingKit也加快了SenTestingKit框架的编译速度,并允许我从所有测试文件的顶部省略{{1}}。
答案 3 :(得分:16)
我决定在代码本身添加一个环境变量检查,而不是使用Robert提出的isRunningTests()建议。
+ (BOOL) isTesting { NSDictionary* environment = [[NSProcessInfo processInfo] environment]; return [environment objectForKey:@"TESTING"] != nil; }
完成后,屏幕应如下所示。
在测试模式或应用程序模式下运行时,上面的代码将找到TESTING环境变量。此代码在您的应用程序中,而不是单元测试文件。你可以使用
#ifdef DEBUG
...
#endif
防止代码在生产中执行。
答案 4 :(得分:4)
Robert在SWIFT 3.0中的回答:
func isRunningTests() -> Bool {
let environment = ProcessInfo().environment
return (environment["XCInjectBundleInto"] != nil);
}
答案 5 :(得分:2)
我测试了这么长时间,发现了一个结果:
您不仅可以将前置纵向宏添加到单元测试目标中(您可以使用多种方法 using variables for unit testing only, 并遵循@MattDiPasquale方法),
但您还必须在测试目标中添加条件complie文件。 我们应该重新翻译这个文件,因为你有一个新的预处理器宏,这个文件, 但是这个文件内置了应用程序目标,那时你的预处理器宏没有设置。
希望这对你有所帮助。
答案 6 :(得分:2)
如果您创建一个测试构建配置,然后设置&#34;其他Swift标志&#34;您的目标的属性为&#34; -DTEST&#34;它将定义一个可以在你的swift代码中工作的TEST宏。确保在App目标的构建设置中进行设置,以便在App的Swift代码中使用它。
然后使用此设置,您可以像这样测试您的代码:
func testMacro() {
#if !TEST
// skipping over this block of code for unit tests
#endif
}
答案 7 :(得分:0)
查看环境变量以查看单元测试是否正在运行。与罗伯特的答案类似,但我只是为了表现而检查一次。
+ (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;
}
答案 8 :(得分:0)
在iOS上,[UIApplication sharedApplication]
将在单元测试运行时返回nil
。
答案 9 :(得分:0)
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;
}
答案 10 :(得分:0)
已针对Xcode10更新:
static let isRunningUnitTests: Bool = {
let environment = ProcessInfo().environment
return (environment["XCTestConfigurationFilePath"] != nil)
}()