UITesting, XCTest current ViewController Class
Asked Answered
L

2

25

Simple problem. I got button which perform segue to next view controller. I want to write UI XCTest to tell me did it open view controller i wanted.

Longheaded answered 23/11, 2015 at 13:32 Comment(0)
H
47

The UI Testing framework doesn't have access to your applications code which makes class assertions on instances impossible. You are not able to directly tell the class of the controller which is on screen.

However, if you think about your test a little differently you can make a very similar assertion. Write your tests as if you are the user. Your user doesn't care if he/she is looking at a ItemDetailViewController or a ItemListTableViewController so neither should your tests.

The user cares what's on the screen. What's the title? Or, what are the names of these buttons? Following that logic you are rewrite your test to assert based on those items, not the name of the coded class.

For example, if you are presenting your controller in a navigation stack you can assert the title.

let app = XCUIApplication()
app.buttons["View Item"].tap()

XCTAssert(app.navigationBars["Some Item"].exists)

Or, if the screen is presented modally but you know some static text or buttons, use those.

let app = XCUIApplication()
app.buttons["View Item"].tap()

XCTAssert(app.staticTexts["Item Detail"].exists)
XCTAssert(app.buttons["Remove Item"].exists)
Heribertoheringer answered 23/11, 2015 at 15:19 Comment(4)
In my case, I have to sleep(1) before app.buttons["View Item"].tap() for it to workSkolnik
I feel that there must be a better way of doing this... What happens if when you change text in the app? What happens if you have multiple localisations of the text in the app? It seems that it would require quite a lot of tests if it was localised and a potential maintenance headache if the text needs to change.Scutari
@MattGreen then you have to assign accessibility identifiers to such labels/textfields etc. Then it will be like let button = app.buttons["accessId"], XCTAssertEqual(button.label, "EXPECTED LABEL"), and/or button.tap()Wilkerson
@JoeMasilotti with your method, is it possible to call accessibilityCustomAction with XCUITest, please ?Silent
J
2

Comment of Matt Green gave me a good idea. We can define an unused label/button, ideally inside a base view controller and assign it an accessibility label to perform a query to find out which view controller is presented.

public class BaseViewController: UIViewController {

    let button = UIButton(frame: CGRect(x: 0, y: 0, width: 1, height: 1))

    public override func viewDidLoad() {
        super.viewDidLoad()
        if let identifier = self.theClassName.split(separator: ".").last {
            button.accessibilityIdentifier = String(identifier)
            view.addSubview(button)
        }
    }
}

public class DatePickerViewController: BaseViewController {
   ...
}

func testExample() {
    let app = XCUIApplication()
    app.launch()
    app.navigationBars.buttons["DateSelector"].tap()
    XCTAssertTrue(app.buttons["DatePickerViewController"].exists)
}

Note that inorder to make this approach work you have to add the view you use to identify view controller, in this case a button, should be added as a sub view and has to have a non zero frame.

Jase answered 21/2, 2020 at 12:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.