Xcode UI Test Example

Xcode UI Test example

Use Unit Tests to test the validity of methods in your classes. You use them to test the code you have written. (See my other example for setting up a simple Unit Test in Xcode.)

Use UI Tests to check the validity of the User Interface. Think of it like having your own robot to go through and do all the normal interactions with your app that a normal user would. This saves you the time of doing it yourself.

At the time of this writing, it is difficult to access many of the properties of the UI components, but just having a test go through tapping them and swiping them confirms that they are there.

Example

This is about the simplest setup and UI test that I could think of: a button that when pressed changes the text of a label.

Set up

  • Create a new project in Xcode 7+ for iOS 9.0+.
  • Make sure that Include UI Tests is checked

enter image description here

  • If you are adding UI tests to a project created before Xcode 7, see this answer. (File > New > Target > Test > Cocoa Touch UI Testing Bundle)

  • Add a UILabel and a UIButton to the storyboard

enter image description here

  • Create an @IBOutlet and @IBAction in the ViewController and make the label text change when the button is pressed.

    import UIKit
    class ViewController: UIViewController {
    @IBOutlet weak var label: UILabel!
    @IBAction func button(sender: AnyObject) {
    label.text = "Hello"
    }
    }

Do the test

  • Open the YourProjectUITests file.

enter image description here

  • Put your curser in the testExample() method. (You can delete the comments)

enter image description here

  • Press the red Record button

enter image description here

  • In the app, (1) tap the label, (2) tap the button, and then (3) tap the label again. (4) Press the Record button again to stop recording. The following code should have been automatically generated for you:

    func testExample() {

    let app = XCUIApplication()
    app.staticTexts["Label"].tap()
    app.buttons["Button"].tap()
    app.staticTexts["Hello"].tap()
    }
  • Use the staticText lines as a starting point for making an XCTAssert. Now you should have:

    func testExample() {

    let app = XCUIApplication()
    XCTAssert(app.staticTexts["Label"].exists)
    app.buttons["Button"].tap()
    XCTAssert(app.staticTexts["Hello"].exists)
    }
  • Press the diamond on the left to run the UI Test. It should turn green when it passes.

enter image description here

  • That's it! This showed that the UIButton and UILabel exist and that the text of the label changed. If you want to see it fail (a good idea), you can change "Hello" to something else.

Further study

  • UI Testing in Xcode
  • Exploring the New UI Testing Features of Xcode 7
  • Xcode 7 UI testing, a first look
  • UI Testing in Xcode 7

How to correctly write a UI test for a Swift UI Toggle

I got a few responses in some slack channels and it turns out that for some reason using a Toggle I can't rely on the default label for testing (unlike Text and Button) and need to create a custom accessibility identifier.

So just add something like this:

    Toggle("Test switch", isOn: $toggleValue)
.padding()
.accessibilityIdentifier("testSwitch")

and then test like this works:

func testExample() throws {
let app = XCUIApplication()
app.launch()
XCTAssertTrue(app.switches["testSwitch"].isEnabled)
XCTAssertTrue(app.switches["testSwitch"].value as? String == "1")
}

Accessing project files from XCode UI Test Target

Using the new UI automation framework Apple introduced in WWDC 15 it is not possible to access your app's code from the UI-Automation test. It's meant to simulate what a user would have access too, which can be frustrating at times.

The UI tests are a separate module from the app, therefore not run inside your app as a logic test would. The only way for them to share code is to compile in all the app files you need to share between the two modules. Hope that helps.

iOS UI Testing vs Integration Testing

UI and Integration testing are fairly different concepts. UI Testing is testing the UI specifically, such as "When I press the login button, the credentials are validated and the page transitions to the home page". While an integration test is to evaluate how different components work together.

Testing is usually thought of as unit testing, but in reality most tests you write are most likely integration tests. While a unit test is supposed to test a "unit" of code such as a function, an integration test will test the use of a bunch of functions "integrated" together.

UI tests become necessary when you can't test certain aspects of your app using some input/output validation or need to test the flows of the app. You would write a unit test for credential validation: does username/password meet the requirements. An integration test to validate retrieving a full User object when logging in a user (assuming you mock the database/network layers), and a UI test to test the login form doing all these.

In the above example, you can see that a unit test may not be as necessary since the integration test will also touch on the individual functions. You should unit specific behavior, such as a user trying the known invalid parameters do in fact fail, i.e. SQL injection.

Straightforward yet isolated view controller UI testing in Xcode Simulator possible?

You cannot manually initialize a UIViewController (or any other UIKit class) in your XCTestCase Class and run UITests on it.

Your UITest test code runs as a separate process, synthesizing events that UI in your app responds to. In other words, the code that you write in your UITests runs on a Test Runner App that interacts with the App that your testing. The Test Runner app can only interact with the main app's UI Elements. It cannot access the main app's code or view hierarchy directly. So you cannot add a UIViewController during a test.

As you already mentioned in your question you could add another target that only shows the View Controller you want to test. But that does not sound very practical to me.

Or (as you also mentioned) you could set XUIApplication().launchArguments in your UITest and present the ViewController directly on app start when the launch arguments have been set.



Related Topics



Leave a reply



Submit