Cannot Access Appdelegate While Testing Xcode Project

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



Leave a reply



Submit