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.
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") }
}
}
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:
import UIKit
private func delegateClassName() -> String? {
return NSClassFromString("XCTestCase") == nil ? NSStringFromClass(AppDelegate.self) : nil
}
UIApplicationMain(
CommandLine.argc,
CommandLine.unsafeArgv,
nil,
delegateClassName()
)
import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate {
}