Xcode:测试与调试预处理器宏
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6748087/
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
Xcode: TEST vs DEBUG preprocessor macros
提问by ma11hew28
When creating a new project with unit tests, Xcode sets the build configuration to Debug for the Test scheme (same for the Run scheme).
在创建带有单元测试的新项目时,Xcode 将构建配置设置为 Test 方案的 Debug(与 Run 方案相同)。
Should I differentiate between Run (Command-R) & Test (Command-U) schemes?
我应该区分运行 (Command-R) 和测试 (Command-U) 方案吗?
I.e., should I create a new Build Configuration called Test, add a preprocessor macro TEST=1 to it, and use it as the build configuration for the Test scheme instead? Or, should I just keep Run & Test both as Debug?
即,我应该创建一个名为 Test 的新构建配置,向其中添加一个预处理器宏 TEST=1,并将其用作测试方案的构建配置吗?或者,我应该将 Run & Test 都保留为 Debug 吗?
I come from a Ruby/Rails background, where you usually have test, development, and production environments. It seems to me that Debug is like development and Release is like production, but we're missing a test, which is why I'm thinking it might make sense to add Test.
我来自 Ruby/Rails 背景,您通常拥有测试、开发和生产环境。在我看来,Debug 就像开发,Release 就像生产,但是我们缺少测试,这就是为什么我认为添加 Test 可能有意义。
Comments? Opinions? Suggestions?
注释?意见?建议?
I'm specifically asking this because I want to compile something for Test with:
我特别问这个是因为我想编译一些用于测试的东西:
#ifdef TEST
// Do something when I test.
#endif
I don't think it matters if I also compile this for Debug. So, I really could just do:
如果我也为 Debug 编译它,我认为这并不重要。所以,我真的可以这样做:
#ifdef DEBUG
// Do something when I run or test.
#endif
But, I'm really only intending to do it for tests for now. So, that's why I'm thinking I should differentiate between debug & test but am wondering why Xcode doesn't do that for you by default? Does Apple think you shouldn't differentiate between them?
但是,我现在真的只想做测试。所以,这就是为什么我认为我应该区分调试和测试,但我想知道为什么 Xcode 在默认情况下不为您这样做?苹果认为你不应该区分它们吗?
采纳答案by ma11hew28
Instead of creating a Test build configuration, I:
我没有创建测试构建配置,而是:
created a
Tests-Prefix.pch
file:#define TEST 1 #import <SenTestingKit/SenTestingKit.h> #import "CocoaPlant-Prefix.pch"
entered its path in the Prefix Header field of the Tests target's build settings.
added the following code to the top of a file I created called
MyAppDefines.h
, imported inMyApp-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
创建了一个
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
This allows me to use BUNDLE
where ever I mean [NSBundle mainBundle]
and also have it work when I run Tests.
这使我可以BUNDLE
在任何我想使用的地方使用[NSBundle mainBundle]
它,并且在我运行测试时也可以使用它。
Importing SenTestingKit in Tests-Prefix.pch
also speeds up the compiling of the SenTestingKit Framework and allows me to leave out #import <SenTestingKit/SenTestingKit.h>
from the top of all the tests files.
导入 SenTestingKitTests-Prefix.pch
还加快了 SenTestingKit 框架的编译,并允许我#import <SenTestingKit/SenTestingKit.h>
从所有测试文件的顶部省略。
回答by Robert
Preprocessor macros will not work, you need to check the environment at runtime.
预处理器宏不起作用,您需要在运行时检查环境。
Objective-c
目标-c
static BOOL isRunningTests(void)
{
NSDictionary* environment = [[NSProcessInfo processInfo] environment];
return (environment[@"XCTestConfigurationFilePath"] != nil);
}
Swift
迅速
var unitTesting : Bool
{
return ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil
}
(Updated for Xcode 11)
(针对 Xcode 11 更新)
回答by David
You might consider adding a new build configuration.
您可能会考虑添加新的构建配置。
In xcode 4, click on your project on the left hand navigator.
在 xcode 4 中,单击左侧导航器上的项目。
In the main window, click on your project, and then select the "info" tab.
在主窗口中,单击您的项目,然后选择“信息”选项卡。
Click the "+" button to add a new configuration (you can call yours "test" if you like").
单击“+”按钮添加新配置(如果您愿意,可以将您的配置称为“测试”)。
Now, click on your target, and go to the build settings tab.
现在,单击您的目标,然后转到构建设置选项卡。
Search for "preprocessor macros"
搜索“预处理器宏”
Here, you can add preprocessor macros for your new build configuration.
在这里,您可以为新的构建配置添加预处理器宏。
Just double click on your new "test" configuration, and add TESTING=1.
只需双击您的新“测试”配置,然后添加 TESTING=1。
Finally, edit your build scheme. Select the test options for your scheme. There should be a "Build Configuration" drop down menu. Select your "test" configuration.
最后,编辑您的构建方案。为您的方案选择测试选项。应该有一个“构建配置”下拉菜单。选择您的“测试”配置。
回答by focused4success
I decided to add a check for an environment variable in the code itself, instead of using the isRunningTests() suggestion Robert made.
我决定在代码本身中添加对环境变量的检查,而不是使用罗伯特提出的 isRunningTests() 建议。
- Edit the current Scheme (Product/Scheme/Edit Scheme) or Command+<
- Click on the Test configuration
- Click on Arguments Uncheck "Use the Run action's arguments and environment variables
- Expand Environment Variable section and add the variable TESTING with value YES
- Add this to your code somewhere and call is whenever you need to:
- 编辑当前方案(产品/方案/编辑方案)或 Command+<
- 点击测试配置
- 单击参数取消选中“使用运行操作的参数和环境变量
- 展开 Environment Variable 部分并添加值为 YES 的变量 TESTING
- 将此添加到您的代码中的某处,并在您需要时调用:
+ (BOOL) isTesting { NSDictionary* environment = [[NSProcessInfo processInfo] environment]; return [environment objectForKey:@"TESTING"] != nil; }
+ (BOOL) isTesting { NSDictionary* environment = [[NSProcessInfo processInfo] environment]; return [environment objectForKey:@"TESTING"] != nil; }
The screen should look like this when you are done.
完成后,屏幕应如下所示。
The code above will find the TESTING environment variable when running in test mode or application mode. This code goes in your application, not the unit test files. You can use
上面的代码在测试模式或应用程序模式下运行时会找到TESTING环境变量。此代码位于您的应用程序中,而不是单元测试文件中。您可以使用
#ifdef DEBUG
...
#endif
To prevent the code from being executed in production.
防止代码在生产中被执行。
回答by Houman
Robert's answer in SWIFT 3.0:
罗伯特在 SWIFT 3.0 中的回答:
func isRunningTests() -> Bool {
let environment = ProcessInfo().environment
return (environment["XCInjectBundleInto"] != nil);
}
回答by ucangetit
If you create a Test build configuration and then set the "Other Swift Flags" property of your Target to "-DTEST" it will define a TEST macro that will work in your swift code. Make sure you set it in the build settings of your App target so that you can use it in your App's Swift code.
如果您创建一个测试构建配置,然后将目标的“其他 Swift 标志”属性设置为“-DTEST”,它将定义一个可以在您的 Swift 代码中工作的 TEST 宏。确保在 App 目标的构建设置中设置它,以便您可以在 App 的 Swift 代码中使用它。
Then with this set, you can test your code like so:
然后使用这个集合,你可以像这样测试你的代码:
func testMacro() {
#if !TEST
// skipping over this block of code for unit tests
#endif
}
回答by raf
Updated for Xcode10:
为 Xcode10 更新:
static let isRunningUnitTests: Bool = {
let environment = ProcessInfo().environment
return (environment["XCTestConfigurationFilePath"] != nil)
}()
回答by regrecall
I test such a long time, found a result:
我测试了这么久,发现了一个结果:
Not only you add the preproessor macro into your unit test target(You could have many methods using variables for unit testing only, and follow the @MattDiPasquale methods),
不仅您将预处理器宏添加到您的单元测试目标中(您可以有许多 只使用变量进行单元测试的方法,并遵循@MattDiPasquale 方法),
but also You must add the condition complie file in your test target. we should recomplie this file, because you have a new preprocessor macro for this file, but this file has built in the application target that time your preprocessor macro didn't set.
但您还必须在测试目标中添加条件编译文件。我们应该重新编译这个文件,因为你有一个新的这个文件的预处理器宏,但是这个文件已经内置在你的预处理器宏没有设置的应用程序目标中。
Hope this help you.
希望这对你有帮助。
回答by Fresh One
Modified version of Kev's answer that works for me on Xcode 8.3.2
在 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;
}
回答by kev
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;
}