I am adding unit tests to an existing SwiftUI project, and I've discovered the main 'App' struct's init() function is being called automatically before the individual test functions are run.
(1) Is this expected behavior?
(2) Is there a way to disable the App struct's init() from being called when running unit tests?
In my use case, the App struct's init() does some initialization, including network activity, that I would prefer not happen during unit tests.
Below is simplified version of what I am seeing beginning with the App struct:
import SwiftUI
import os.log
@main
struct MyTest2App: App {
init() {
os_log("===== In MyTest2App.init() =====")
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Here is an example of a struct that I want to exercise in a unit test:
import Foundation
struct Foo {
var name: String
var count: Int
init(name: String, count: Int) {
self.name = name
self.count = count + 1
}
}
Here is a unit test file:
import XCTest
final class MyTest2Tests: XCTestCase {
override func setUpWithError() throws {
}
override func tearDownWithError() throws {
}
func testExample() throws {
let foo = Foo(name: "Apple", count: 3)
XCTAssertEqual(foo.count, 4)
}
}
Here is part of the output console. The first line is the output from the App struct's init() function:
2023-09-27 10:41:26.798791-0700 MyTest2[66138:9429362] ===== In MyTest2App.init() =====
2023-09-27 10:41:26.869966-0700 MyTest2[66138:9429362] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to /var/folders/yg/vfstql350kqgzp17lmh11jg80000gn/T/com.ennetix.MyTest2/com.ennetix.MyTest2.savedState
...
(1) Is this expected behavior?
Yes. By default your unit test bundle is loaded into your app, and for that to happen the app must be initialised.
(2) Is there a way to disable the App struct's
init()
from being called when running unit tests?
You can change your unit test to not target your app. [Hmmm, I not entirely sure how to do that in this brave new world of test plans but it doesn’t really matter because I think the next option is better.]
A better option is to add arguments to your test plan, read those arguments in init()
, and then customise your init()
behaviour based on that. For example, I added the arguments -QQQ_TEST
and YES
to the test plan, and then added this code to init()
:
print("is testing:", UserDefaults.standard.bool(forKey: "QQQ_TEST"))
It prints true
when testing and false
when running.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"