I've been using the following post as guidance for how to display a UIAlertController
from code that is unrelated to a specific UIViewController
. Now, I want to unit test this code:
func showAlert(alert: UIAlertController, animated: Bool, completion: (()->Void)?)
{
let alertWindow = UIWindow(frame: UIScreen.mainScreen().bounds)
// Keep a strong refence to the window.
// We manually set this to nil when the alert is dismissed
self.alertWindow = alertWindow
alertWindow.rootViewController = UIViewController()
if let currentTopWindow = UIApplication.sharedApplication().windows.last {
alertWindow.windowLevel = currentTopWindow.windowLevel + 1
}
else {
// This case only happens during unit testing
Logger.trace(ICELogLevel.Error, category: .Utility, message: "The application doesn't have a window being displayed!")
}
// preload the viewController for unit testing
// (see https://www.natashatherobot.com/ios-testing-view-controllers-swift/ )
let _ = alertWindow.rootViewController?.view
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController!.presentViewController(self.alertController, animated: animated, completion: completion)
}
However, when running a unit test, on the alertWindow.makeKeyAndVisible()
line, I get an NSInternalInconsistencyException: props must have a valid clientID
.
This code works in the app code, and I'd prefer not to use a mock UIWindow etc, since I'm looking to verify that the alert is actually shown on a real UIWindow.
Any guidance on how we can use UIWindows() in Unit Tests? What am I doing wrong?
The problem is that makeKeyAndVisible
invokes code that internally requires a running UIApplication instance. This is why the exception is thrown when testing a framework but not when testing an application. Application tests inject the test bundle into a running application. The easy workaround is to move from:
alertWindow.makeKeyAndVisible()
To
alertWindow.isHidden = false
This works and allows a view controller to be tested in isolation with a window. The downside is of course that this is not identical to makeKeyAndVisible
- it does not have the side effects that trigger the exception.
Another strategy is to create a new, empty application target exclusively to support testing. Embed the framework under test inside that and use it as the host application for unit tests.