Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift-UITest #113

Open
djk3000 opened this issue Dec 21, 2022 · 0 comments
Open

Swift-UITest #113

djk3000 opened this issue Dec 21, 2022 · 0 comments

Comments

@djk3000
Copy link
Owner

djk3000 commented Dec 21, 2022

Swift中的UITest

UITest和UnitTest又完全不一样了,UITest可以测试用户的界面流程。而不会去测试所有的代码逻辑。

实现

创建步骤

和UnitTest一样在我们的要测试项目中
File->New->Targer->UnitTest Bundle->命名为(项目名_UITest)->Finish

初始Test文件

import XCTest

final class DJKAdvancedLearning_UITests: XCTestCase {
    //把app的创建提取出来
    let app = XCUIApplication()

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.

        // In UI tests it is usually best to stop immediately when a failure occurs.
        continueAfterFailure = false

        // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.

       //初始化创建
        app.launch()
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    func testExample() throws {
        // UI tests must launch the application that they test.
        //不需要每个测试都去初始化一遍,直接用全局的app
        // let app = XCUIApplication()
        // app.launch()

        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    func testLaunchPerformance() throws {
        if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
            // This measures how long it takes to launch your application.
            measure(metrics: [XCTApplicationLaunchMetric()]) {
                XCUIApplication().launch()
            }
        }
    }
}

这里和UnitTest不一样的地方在于,不需要每个测试都去创建Application,只要在初始化的时候创建一次。

命名规则

这里参考UnitTest一样

编写用例

    func test_UITestBootcampView_signUpButton_shouldSign() {
        
        let app = XCUIApplication()
        app.keys["A"].tap()
        
        let aKey = app.keys["a"]
        aKey.tap()
        aKey.tap()
        app.buttons["SignUpButton"].tap()
        app.buttons["ShowAlertButton"].tap()
        app.alerts["Welcome to app"].scrollViews.otherElements.buttons["OK"].tap()
        
    }

这里的代码是我通过XCode自带的模拟器操作来自动编写出来的,然后再自己修改这个用例,这个是原始的,操作如下:

2022-12-21.14.50.08.mov

修改后的例子

    func test_UITestBootcampView_signUpButton_shouldSignIn() {
        //Given
//        let addYourNameTextField = app.textFields["Add Your Name"]
        let addYourNameTextField = app.textFields["SignUpTextField"]
        addYourNameTextField.tap()
        //When
        app.keys["A"].tap()
        
        let aKey = app.keys["a"]
        aKey.tap()
        aKey.tap()
        aKey.tap()
        aKey.tap()
        app.buttons["Return"].tap()
        app.buttons["SignUpButton"].tap()
        let navigationBar = app.navigationBars["Welcome"]
        
        //Then
        XCTAssertTrue(navigationBar.exists)
    }

一些小技巧

  1. 可以通过在View上添加accessibilityIdentifier来讲Test中的Name变为固定的控件,而不是通过Text的String来判断,不然如果这个String更改了就需要更改测试用例。
TextField(vm.placeFolder, text: “Add Your Name”)
                .font(.headline)
                .padding()
                .background(Color.white)
                .cornerRadius(10)
                .accessibilityIdentifier("SignUpTextField")
测试使用:
//        let addYourNameTextField = app.textFields["Add Your Name"]
        let addYourNameTextField = app.textFields["SignUpTextField"]
  1. 判断的话同样是使用XCTAssert()的一些方法来进行判断,增加了一些UI的判断比如:
//在屏幕上组件是否存在(显示)
let buttonIsExists = app.buttons["back"].exists
//组件存在且当前位置可以点击,若被覆盖則為false
let buttonIsHittable = app.buttons["back"].isHittable 
  1. 当点击框出现和消失的时候,可能太快了测试会捕捉不到,这时候可以添加sleep(1)时间,或者等待超时来等待我们的控件显示或者消失
    func test_signInHomeView_showAlertButton_shouldDisplayAndDismissAlert() {
        //Given
        app.textFields["SignUpTextField"].tap()
        
        //When
        let aKey = app.keys["A"]
        aKey.tap()
        
        let aKey2 = app.keys["a"]
        aKey2.tap()
        aKey2.tap()
        aKey2.tap()
        aKey2.tap()
        app.buttons["Return"].tap()
        app.buttons["SignUpButton"].tap()
        app.buttons["ShowAlertButton"].tap()
        
        //Then
        let alert = app.alerts.firstMatch
        XCTAssertTrue(alert.exists)
        
        let okButton = alert.buttons["OK"]
        
        //等待button的显示,如果5秒不显示测测试失败
        let existOKButtonAlert = okButton.waitForExistence(timeout: 5)
        XCTAssertTrue(existOKButtonAlert)
        
        okButton.tap()
        
        let existAlert = alert.waitForExistence(timeout: 3)
        
//        sleep(1) 也可以使用sleep等待,如果控制不好时间的话还是超时比较方便
        XCTAssertFalse(existAlert)
        XCTAssertFalse(alert.exists)
        
    }
  1. 可以在App启动的时候添加参数和环境变量,可以对环境变量和参数进行判断增加测试的便捷性。
    在Product->Scheme->Edit Scheme -> Run或者在选择ios模拟器的旁边也有这个选项。具体也可以看这里

image

import SwiftUI

@main
struct DJKAdvancedLearningApp: App {
    
    init() {
        let userSignIn1: Bool = CommandLine.arguments.contains("-UITest_startSigIn")
        let userSignIn2: Bool = ProcessInfo.processInfo.arguments.contains("-UITest_startSigIn")
        
        let value = ProcessInfo.processInfo.environment["-UITest_startSigIn2"]
        print("User Sign IN1 \(userSignIn1)")
        print("User Sign IN2 \(userSignIn2)")
        print("User Sign IN3 \(value)")
    }
    
    var body: some Scene {
        WindowGroup {
            UITestingBootcampView()
        }
    }
}
  1. 因为每次机器编写的代码很多都是重复的,有洁癖的可以把一些公共方法提取出来,具体就看每个人怎么写了,这里就不举例了。

参考资料

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant