Reputation: 139
When I call
UIApplication.shared.keyWindow
to try and set the root view controller in my test class, the key window returns nil. Why is this happening?
Here's how I set up my storyboard:
let testBoard = UIStoryboard(name: "TestStoryboard", bundle: Bundle(for: type(of: self)))
let vc = testBoard.instantiateViewController(withIdentifier: "TestController")
UIApplication.shared.keyWindow?.rootViewController = vc
_ = vc.view
vc.viewDidLoad()
Upvotes: 8
Views: 5128
Reputation: 2041
I had a similar problem when testing UI inside a library that required access to a real UIWindow but had no test app of it's own.
My workaround was to add a dummy iOS single view target, then assign that as the unit tests host application.
This of course gives your test code a UIApplication singleton complete with delegate and window to play with.
import XCTest
import UIKit
class ExampleTestCase: XCTestCase {
var rootViewController: UIViewController!
override func setUp() {
guard let mainWindow = UIApplication.shared.delegate?.window,
let window = mainWindow else {
fatalError("Unable to find window")
}
rootViewController = UIViewController()
window.rootViewController = rootViewController
setupView()
window.makeKeyAndVisible()
RunLoop.current.run(until: Date())
}
func setupView() {
rootViewController.view.backgroundColor = .red
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
label.text = "Hello!"
label.textColor = .white
label.font = UIFont.systemFont(ofSize: 25)
//Do something with window
rootViewController.view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.centerXAnchor.constraint(equalTo: label.superview!.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: label.superview!.centerYAnchor).isActive = true
}
func testExample() {
print("Im a useless test!")
}
}
Upvotes: 0
Reputation: 3940
Create a window and assign the view controller.
let testBoard = UIStoryboard(name: "TestStoryboard", bundle: Bundle(for: type(of: self)))
let vc = testBoard.instantiateViewController(withIdentifier: "TestController")
let window = UIWindow()
window.rootViewController = vc
window.makeKeyAndVisible()
vc.view.layoutIfNeeded()
// Add test here
I notice after that you're also calling vc.view
and viewDidLoad
. I'd recommend just accessing the view to get it to load and not calling viewDidLoad
implicitely - personally I use vc.view.layoutIfNeeded()
Depending on what you actually need to test, for me it's very rare to have to assign the view controller to the window itself. You can normally get away with just creating an instance of the view controller, and if you're testing any of the UI code also ensuring the view is populated.
One of the only times I've needed to assign the view controller to a window is when testing things like navigation, where I want to assert that another view controller is being presented modally due to some action.
Upvotes: 11