XCTestCase 中未调用 UITextFieldDelegate

UITextFieldDelegate not called in XCTestCase

我刚刚开始熟悉使用 XCTestCase 编写测试并探索其功能。我有一个简单的(如果设计的)应用程序,它加载一个带有按钮和文本字段的屏幕。选择文本字段时,视图控制器填充文本字段:

public func textFieldDidBeginEditing(_ textField: UITextField) {
    textField.text = "abcd"
}

我还有按下按钮时选择字段的功能:

@IBAction public func selectField(_ sender: Any?) {
    print("button press")
    textfield.becomeFirstResponder()
}

我的测试用例中的代码,使用 vc.button.sendActions(for: .touchUpInside)

以编程方式点击按钮

但是,文本字段似乎并没有成为第一响应者,因此没有调用委托方法。下面是完整的测试用例 class:

var vc: ViewController!

override func setUp() {
    let sb = UIStoryboard(name: "Main", bundle: nil)
    vc = sb.instantiateInitialViewController() as? ViewController
    _ = vc.view
}

override func tearDown() {

}

func test_textfieldPopulatesOnSelection() {

    vc.button.sendActions(for: .touchUpInside)

    let expectation = XCTestExpectation(description: "waiting for textfield to become first responder")
    DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
        print("textfield.text: \(self.vc.textfield.text ?? "")")
        expectation.fulfill()
    }

    wait(for: [expectation], timeout: 13.0)
}

虽然我意识到我可能混淆了 UI 测试和单元测试的概念,但我仍然很好奇为什么我的委托方法没有被调用。

单元测试中不调用委托方法。调用委托方法取决于测试,就像它们被 Cocoa Touch 调用一样。

所以要测试textFieldDidBeginEditing(_),单元测试需要显式调用它。

I have a simple (if contrived) app that loads a screen with a button and a textfield

不,你没有——至少在这个概念的任何有意义的意义上都没有 "loads a screen"。您有一个视图控制器及其视图,在 setup 中创建,但您尚未对它们进行任何操作。视图控制器不是应用程序视图控制器层次结构的一部分,它的视图不在界面中,因此它包含的文本字段不在界面中。不在界面中的文本字段不会任何事情。它不可能是第一响应者,因为它没有什么可以响应的。第一响应者是应用 window 的一项功能,您的文本字段不是 in 中的任何 window。

无论如何,您在这里使用单元测试是错误的。与其说是将单元测试与用户界面测试混为一谈,不如说是将单元测试与用户界面测试混为一谈。这是因为您没有专注于 的测试。没有必要测试说 becomeFirstResponder 使文本字段成为第一响应者的概念;你知道那是真的,所以没有什么可检验的。您在单元测试中的工作是测试 应用程序的功能,而不是测试 Cocoa 框架。