Xcode project how to detect target programmatically or how to use env vars

空扰寡人 提交于 2019-11-28 06:18:38
jpswain

Never mind... figured out that it is in "Schemes" that you set this.

For example if you want TARGET=TEST to be available during Test and TARGET=RUN to show during run, just set that in your Scheme > Environment Variables > Name/Value.

Then from your app you can do:

[[[NSProcessInfo processInfo] environment] objectForKey:@"TARGET"]

Using build settings with preprocessor macros DID NOT work for me b/c my test target (for application/integration testing) is dependent on my main (not test) target, so the main target is built first and that's what runs, and you end up with main target preprocessor macros even though you are after the ones defined in the target you ran. If I missed something here someone feel free to explain please.

If by "test target" you mean your unit tests (i.e. Product > Test or ⌘U), you can add a preprocessor macro to the target and check for that macro in your code. This allows something like the following:

#ifdef TEST
  // Load the hard-coded data.
#else
  // Load data from the server.
#endif

To do this, click on your project file in the project navigator, select your test target, click the Build Settings tab, search for "macros", double click the Preprocessor Macros option, and add one!

There two situations to deal with:

  1. Run some code if a certain target such as Tests is selected, and
  2. Conditionally #import some files for a certain target such as Tests.

Target Code for Test Target:

Create a macro in your ProjectName-Prefix.pch file as following:

#define IsTestTarget [[[[NSProcessInfo processInfo] environment][@"XCInjectBundle"] pathExtension] isEqualToString:@"xctest"]

and then call it anywhere in the app:

if (IsTestTarget) {
    //Do something specific for test target;
} else {
    //Otherwise do something else
}

Conditional #import:

To #import certain files when Tests target is selected, you do need to add a Preprocessor Macro to your Test target and use it as:

#ifdef APPTESTS
    #import "TestSpecificFile.h"
#else
    #import "SomeOtherFile.h"
#endif 

Here is how you can add a Preprocessor Macro:

You can use the below function.

+(BOOL)  isRunningTests
{
    NSDictionary* environment = [[NSProcessInfo processInfo] environment];
    NSString* injectBundle = environment[@"XCInjectBundle"];
    return [[injectBundle pathExtension] isEqualToString:@"xctest"];
}

Usually in Unit Test programmers are using mocking classes and functionalities. You can create a class with target membership only for the test target.

@interface MockClass : NSObject

@end

Then in the application code you can check if class exist using NSClassFromString function (which will return Nil for target not included in the class's target membership, in this case - non test target.

if (NSClassFromString(@"MockClass")) {
    //Test Target
} else {
    //App Target
}

And you can of curse function it

BOOL isUnitTest(){
    return NSClassFromString(@"MockClass") != Nil;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!