How to access the App Delegate from a UI Test?
Xcode UI testing is designed such that the test code can only see what a user can see, so no objects from the application under test can be used or inspected in the test code. This is also why the views on the screen are represented as XCUIElement objects instead of UIView descendants.
The UI tests run in a separate executable from the application under test. The only way to communicate additional information from the app to a UI test is by constructing a string containing the information and using it as the accessibility identifier for an element.
If you want to test something that requires access to an object from the application code, it is most likely that you need to write a unit test instead of a UI test.
Swift: How to not load AppDelegate during Tests
After days of trying and failing I found an answer on the Apple forums:
The problem was that my main.swift file was initializing my AppDelegate before NSApplication had been initialized. The Apple documentation makes it clear that lots of other Cocoa classes rely on NSApplication to be up and running when they are initialized. Apparently, NSObject and NSWindow are two of them.
So my final and working code in main.swift
looks like this:
private func isTestRun() -> Bool {
return NSClassFromString("XCTest") != nil
}
private func runApplication(
application: NSApplication = NSApplication.sharedApplication(),
delegate: NSObject.Type? = nil,
bundle: NSBundle? = nil,
nibName: String = "MainMenu") {
var topLevelObjects: NSArray?
// Actual initialization of the delegate is deferred until here:
application.delegate = delegate?.init() as? NSApplicationDelegate
guard bundle != nil else {
application.run()
return
}
if bundle!.loadNibNamed(nibName, owner: application, topLevelObjects: &topLevelObjects ) {
application.run()
} else {
print("An error was encountered while starting the application.")
}
}
if isTestRun() {
let mockDelegateClass = NSClassFromString("MockAppDelegate") as? NSObject.Type
runApplication(delegate: mockDelegateClass)
} else {
runApplication(delegate: AppDelegate.self, bundle: NSBundle.mainBundle())
}
So the actual problem before was that the Nib was being loaded during tests. This solution prevents this. It just loads the application with a mocked application delegate whenever it detects a test run (By looking for the XCTest
class).
I'm sure I will have to tweak this a bit more. Especially when a start with UI Testing. But for the moment it works.
Related Topics
Calculate New Coordinates with Starting Position and Distance
iOS 10.3 - How to Change App Icon Programmatically
Why Is Uisearchcontroller Changing the Navigation Bar Colors
Swift - Uitableview Didselectrowatindexpath & Diddeselectrowatindexpath Add & Remove Indexpath Ids
Uitableviewcell Initwithstyle:Uitableviewcellstylesubtitle Is Not Working
How to Make a Rounded Oval Button
How to Work with Udp Sockets in iOS, Swift
Sync Data Between Two Viewcontrollers to Avoid Creating Same Observer Again
If Let Doesn't Unwrap Optional Value for Mkannotation's Title Property
Swift 3 Filter Array of Dictionaries by String Value of Key in Dictionary
How to Pass a Swift Object to JavaScript (Wkwebview/Swift)
Clipping Sound with Opus on Android, Sent from iOS
Lineargravityfield() Is Not Affecting Physics Bodies in the Scene Scenekit
Multiple Cells Selected on Scrolling [Reuse Cells Problem]
How to Use Tap Gesture in Accessibility in Swift
Running an iOS7 Project Under Xcode 6 - Image Assets Don't Show Up