Skip to main content

Command Palette

Search for a command to run...

Faster unit tests by not running the app startup logic

How to bypass the iOS app when running unit tests

Published
2 min read
Faster unit tests by not running the app startup logic
M

I am a Software Engineer working on open source and enterprise mobile SDKs for iOS and MacOS developers written in Swift. From 🇩🇪 and happily living in 🇺🇸

Running unit tests in Swift will launch the (iOS) simulator and the app to which the unit test target belongs. The app probably has some startup logic, e.g asking a remote API for new data, loading information from the local storage, registering for push notifications, etc. These activities are unnecessary when running the unit tests.

it can meddle with the global state, resulting in hard to diagnose failures. Sometimes, it can even make the tests noticeably slower or log noise into your analytics.

I found two insightful articles from Gio Lodi on his blog https://mokacoding.com/ about this topic.

He also shares detailed examples on GitHub. Below you find code snippets for quick reference.

SwiftUI

Here is the recipe to load a different App when running unit tests in a SwiftUI project.

// (c) 2016 - 2020 Gio Lodi @mokagio - mokacoding ☕️

// AppLauncher.swift
import SwiftUI

@main
struct AppLauncher {

    static func main() throws {
        if NSClassFromString("XCTestCase") == nil {
            MyAwesomeApp.main()
        } else {
            TestApp.main()
        }
    }
}

struct TestApp: App {

    var body: some Scene {
        WindowGroup { Text("Running Unit Tests") }
    }
}

// MyAwesomeApp.swift
import SwiftUI

struct MyAwesomeApp: App {

    var body: some Scene { ... }
}

UIKit

Here is the recipe to have a dedicated AppDelegate when running unit tests in a UIKit project:

// (c) 2016 - 2020 Gio Lodi @mokagio - mokacoding ☕️

// main.swift
import UIKit

private func delegateClassName() -> String? {
  return NSClassFromString("XCTestCase") == nil ? NSStringFromClass(AppDelegate.self) : nil
}

UIApplicationMain(
  CommandLine.argc,
  CommandLine.unsafeArgv,
  nil,
  delegateClassName()
)

// AppDelegate.swift
import UIKit

class AppDelegate: UIResponder, UIApplicationDelegate {
  // ...
}

More from this blog

Dev blog post potpourri by senior software engineer Marco Eidinger

149 posts

Hello 👋🏻 , I am a Software Engineer working on open source and enterprise mobile SDKs for iOS and MacOS developers written in Swift. From 🇩🇪 and happily living in 🇺🇸