XCTestCase: UIApplication.shared.keyWindow returns 无

XCTestCase: UIApplication.shared.keyWindow returns nil

当我打电话给

UIApplication.shared.keyWindow

尝试在我的测试中设置根视图控制器 class,键 window returns 无。为什么会这样?

以下是我设置故事板的方式:

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()

创建一个 window 并分配视图控制器。

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

之后我注意到您还调用了 vc.viewviewDidLoad。我建议只访问视图以加载它而不是隐式调用 viewDidLoad - 我个人使用 vc.view.layoutIfNeeded()

根据您实际需要测试的内容,对我来说很少需要将视图控制器分配给 window 本身。通常,您只需创建一个视图控制器的实例即可,如果您正在测试任何 UI 代码,还要确保视图已填充。

我唯一需要将视图控制器分配给 window 的情况之一是在测试导航之类的东西时,我想断言另一个视图控制器由于某些操作而以模态方式呈现.

我在需要访问真实 UIWindow 但没有自己的测试应用程序的库中测试 UI 时遇到了类似的问题。

我的解决方法是添加一个虚拟 iOS 单一视图目标,然后将其指定为单元测试主机应用程序。

这当然会为您的测试代码提供一个 UI带有委托和 window 的应用程序单例。

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!")
    }
}