如何为 SwiftUI InputField 编写 UI 测试

Posted

技术标签:

【中文标题】如何为 SwiftUI InputField 编写 UI 测试【英文标题】:How can I write UI tests for a SwiftUI InputField 【发布时间】:2021-05-20 11:07:23 【问题描述】:

我有这个 SwiftUI 视图(将删除不相关的部分)

struct LoginView: View 
    
    var body: some View 
        VStack 
            Spacer()
            InputField(title: "Email", text: $email)
            InputField(title: "Password", text: $password, showingSecureField: true)
            InputField(title: "Store", text: $userStore)
            CallToActionButton(
                title: newUser ? "Register User" : "Log In",
                action: userAction
            )
            Button(action:  newUser.toggle() ) 
                HStack 
                    CheckBox(title: "Create Account", isChecked: $newUser)
                    Spacer()
                
            
            Spacer()
        
    

我可以使用以下代码为该按钮编写 UI 测试:

    func testClickLoginButton() throws 
        let app = XCUIApplication()
        app.launch()
                  
        let startButton = app.buttons["Log In"]
        XCTAssertTrue(startButton.waitForExistence(timeout: 1))
        XCTAssertTrue(startButton.isEnabled)
        startButton.tap()
    

而且它有效,因为屏幕上有一个带有该标题的按钮。

但是我想自动在这些 InputTexts 中放入一些文本并测试它们,但找不到它们,因为它们既不是 UITextField 也不是 UITextView。我怎样才能做到这一点?谢谢!

    func testAddEmail() throws 
        let app = XCUIApplication()
        app.launch()

        // fails as can't find any text field containing "Email"
                           
        let emailText = app.textFields["Email"]
        XCTAssertTrue(emailText.waitForExistence(timeout: 1))
        emailText.typeText("testemail@realm.com")
        XCTAssertEqual(emailText.value as! String, "testemail@realm.com")
    

【问题讨论】:

【参考方案1】:

如何添加:

 InputField(title: "Email", text: $email)
        .accessibility(identifier: "email_input")

对于您想从 UI 测试中测试的任何其他元素也是如此?

【讨论】:

【参考方案2】:

我不是专家,我见过在 SwiftUI 中进行 UITests 的不同方法。快照等可能有更好的方法,但我很快重新创建了您的示例,并添加了一个可访问性标识符:

struct InputField: View 
    var title: String
    @Binding var email: String

    var body: some View 
        VStack(alignment: .leading) 
            Text("Enter your email ")
            TextField(title, text: $email)
                .accessibility(identifier: "Email")

        
        .padding()
    


struct ContentView: View 
    @State private var email: String = ""

    var body: some View 
            InputField(title: "Email: ", email: $email)
    

此外,有时可能需要在输入电子邮件或文本之前添加一个点击。因此,它给了我一个错误。 UItest 看起来像这样并且正在通过:)

    func testAddEmail() throws 
        let app = XCUIApplication()
        app.launch()

        let emailText = app.textFields["Email"]
        XCTAssertTrue(emailText.waitForExistence(timeout: 1))
        emailText.tap() 
        emailText.typeText("testemail@realm.com")

        XCTAssertEqual(emailText.value as! String, "testemail@realm.com")
    

我学到的一个很酷的技巧是这样设置断点:

并在调试器的提示符处输入以下内容:

(lldb) po XCUIApplication().textFields

所以你得到了这个列表,你看看是否缺少标识符。按钮和静态文本等也是如此。

【讨论】:

以上是关于如何为 SwiftUI InputField 编写 UI 测试的主要内容,如果未能解决你的问题,请参考以下文章

如何为不同环境的 SwiftUI App 生命周期应用程序运行 UI 测试?

如何为 SwiftUI 动态构建视图并呈现它?

在 SwiftUI 中,如何为条形图创建动态矩形?

macOS 上的 SwiftUI:如何为 onDelete 启用 UI(从列表中删除)

如何为视图提供固定位置,使其不受 SwiftUI 中滚动的影响

如何为 SwiftUI 列表中的各个行设置动画?