Marco Eidinger
Swifty Tech by Marco Eidinger

Swifty Tech by Marco Eidinger

Faster unit tests by not running the app startup logic

Photo by Jeswin Thomas on Unsplash

Faster unit tests by not running the app startup logic

How to bypass the iOS app when running unit tests

Marco Eidinger's photo
Marco Eidinger
·May 30, 2022·

2 min read

Subscribe to my newsletter and never miss my upcoming articles

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 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 {
  // ...
}

Did you find this article valuable?

Support Marco Eidinger by becoming a sponsor. Any amount is appreciated!

See recent sponsors Learn more about Hashnode Sponsors
 
Share this