Xcode itself sets environment variables when running tests, so no need to create any in your schemes. If you are already doing so for other purposes, then doing so may be practical. You can, however, use Xcode's environment variables for the purpose of determining whether tests are running. The bulk of the code looks like this in objc, which you could throw into your app delegate:
Option 1:
static BOOL isRunningTests(void) __attribute__((const));
static BOOL isRunningTests(void)
{
NSDictionary* environment = [[NSProcessInfo processInfo] environment];
NSString* injectBundle = environment[@"XCInjectBundle"];
NSLog(@"TSTL %@", [injectBundle pathExtension]);
return [[injectBundle pathExtension] isEqualToString:@"xctest"] || [[injectBundle pathExtension] isEqualToString:@"octest"];
}
Then simply call isRunningTests()
wherever you need to check for tests. This code, however, should really be stored somewhere else, for example, in a TestHelper class:
Option 2:
// TestHelper.h
#import <Foundation/Foundation.h>
extern BOOL isRunningTests(void) __attribute__((const));
// TestHelper.m
#import "TestCase.h"
extern BOOL isRunningTests(void)
{
NSDictionary* environment = [[NSProcessInfo processInfo] environment];
NSString* injectBundle = environment[@"XCInjectBundle"];
NSLog(@"TSTL %@", [injectBundle pathExtension]);
return [[injectBundle pathExtension] isEqualToString:@"xctest"] || [[injectBundle pathExtension] isEqualToString:@"octest"];
}
Note that we are still using the global variable, and the choice of class name is actually irrelevant. It's just some class where it make sense to keep it.
Option 3:
And in swift, you'll need to wrap it in a class in order to work in both objective-c and swift. You could do it like this:
class TestHelper: NSObject {
static let isRunningTests: Bool = {
guard let injectBundle = NSProcessInfo.processInfo().environment["XCInjectBundle"] as NSString? else {
return false
}
let pathExtension = injectBundle.pathExtension
return pathExtension == "xctest" || pathExtension == "octest"
}()
}