Skip to content
Go to file

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

UI Testing UI Testing Example

This sample project shows a different approach to writing UI tests that has a number of benefits:

  • 👩🏻‍🏫 Easier to read
  • 👨🏾‍🔧 Easier to maintain
  • 👩🏼‍💻 Easier to write tests first


UI Testing Process

When implementing a new feature, ideally, you will follow a three-step process:

  1. Write test page objects (see Test Page)
  2. Write failing UI tests (see UI Tests)
  3. Implement feature, making tests pass

Test Page

UI Test Page

A test page object is typically comprised of three parts:

  1. Elements
  2. Actions
  3. Verifications

These sections represent a screen in your app. The elements are private to the page object, and the actions and verifications are the API surface for UI tests to use in validating the behavior of the app.

An element may look something like:

fileprivate var table: XCUIElement {
    return app.tables["MasterViewController.tableView"]

An action is going to return the test page object that is the result of the action, and might look like this:

@discardableResult func tapOnCell(at index: Int, file: String = #file, line: UInt = #line) -> DetailPage {
    let cell = self.cell(at: index)
    testCase.expect(exists: cell, file: file, line: line)
    return DetailPage(testCase: testCase)

Note: We use custom functions instead of XCTAssert to make the testing code more readable. View more in Matchers.swift.

Finally, a verification is a function to use in validating the expected state of the app, and may look like this:

@discardableResult func verifyTableCellCount(is count: Int, file: String = #file, line: UInt = #line) -> MasterPage {
    testCase.expect(exists: table, file: file, line: line)
    testCase.expect(table.cells.count, equals: count, file: file, line: line)
    return self

UI Tests

UI Tests

In the actual UI tests, which are written in a subclass of XCTestCase, you will create a test page object, and call various functions on that object. These tests are exceptional readable, and make it much easier to reason about the behavior that you are expecting as users interact with your app.

An example test for verifying an entry can be added and viewed properly may look like this:

func testAddingEntry() {
    let zeroLabel = "0" 
    MasterPage(testCase: self)
        .verifyTableCellCount(is: 0)
        .verifyTableCellCount(is: 1)
        .verifyCell(at: 0, hasLabel: zeroLabel)
        .tapOnCell(at: 0)
        // Detail page
        .verifyLabelText(is: zeroLabel)
        // Master page


This approach to UI testing has led to significant improvements in our tests and the time it takes to write and maintain them. Hopefully this is helpful to you as well!


Sample project using Apple's Master-Detail App template to demonstrate UI testing




No releases published


No packages published


You can’t perform that action at this time.