How to let the app know if it's running Unit tests in a pure Swift project?

One annoying thing when running tests in Xcode 6.1 is that the entire app has to run and launch its storyboard and root view controller. In my app this runs some server calls that fetches API data. However, I don't want the app to do this when running its tests.

With preprocessor macros gone, what's the best for my project to be aware that it was launched running tests and not an ordinary launch? I run them normally with command + U and on a bot.

Pseudocode:

// Appdelegate.swift
if runningTests() {
   return
} else {
   // do ordinary api calls
}

Elvind's answer isn't bad if you want to have what used to be called pure "Logic Tests". If you'd still like to run your containing host application yet conditionally execute or not execute code depending on whether tests are run, you can use the following to detect if a test bundle has been injected:

if NSProcessInfo.processInfo().environment["XCTestConfigurationFilePath"] != nil {
     // Code only executes when tests are running
}

I used a conditional compilation flag as described in this answer so that the runtime cost is only incurred in debug builds:

#if DEBUG
    if NSProcessInfo.processInfo().environment["XCTestConfigurationFilePath"] != nil {
        // Code only executes when tests are running
    }
#endif

Edit Swift 3.0

if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil {
    // Code only executes when tests are running
}

I use this in application:didFinishLaunchingWithOptions:

// Return if this is a unit test
if let _ = NSClassFromString("XCTest") {
    return true
}

Instead of checking if the tests are running to avoid side-effects, you could run the tests without the host app itself. Go to Project Settings -> select the test target -> General -> Testing -> Host Application -> select 'None'. Just remember to include all files you need to run the tests, as well as libraries normally included by the Host app target.

enter image description here


Other, in my opinion simpler way:

You edit your scheme to pass a boolean value as launch argument to your app. Like this:

Set launch arguments in Xcode

All launch arguments are automatically added to your NSUserDefaults.

You can now get the BOOL like:

BOOL test = [[NSUserDefaults standardUserDefaults] boolForKey:@"isTest"];