let’s dev GmbH & Co. KG - The brand for groundbreaking custom software

Blog

Top!

let’s dev | Scroll to top
let’s dev | Scroll to next content item

Hello

let’s dev | Scroll to previous content item
let’s dev Blog | iOS User Interface Tests
by Nicolas
12. November 2020

iOS User Interface Tests

Automated tests are essential in the development of high-quality apps. Especially when developing the business logic, it is important to cover it with unit tests to be sure that everything works as intended in case of later changes.

In addition to unit tests, there is another form of automated testing, user interface testing, or UI testing for short. While unit tests really focus on a delimited unit or function, UI tests simulate the actual behavior of a user interacting with the app. However, this also means that there are significantly more things to consider so that UI tests are deterministic just like unit tests, i.e. they lead to the same result every time they are run.

This can be demonstrated well using the example of an iOS app. In this example app, there are three functions that can all be tested with UI tests. If a text is entered, it appears in the navigation bar after confirmation. If you press the button, an alert with the title "Good Morning" appears. Finally, the switch can be used to set whether the button can be pressed or not.

UI Test Example

The first UI test

For writing a UI test, Apple's XCTest framework can be used, just like for unit tests. In contrast to unit tests, however, you have to start the app in each test case and describe how to interact with which elements.

Launching the app is done as follows:

let app = XCUIApplication()
app.launch()

The individual UI elements can now be accessed via the app variable. For example, the button in the example above can be read via the title.

let button = app.buttons["Show Alert"]

The disadvantage of this way, however, is that you would have to update the UI test if for some reason the title of the button would change. To avoid this, you can set the accessibilityIdentifier on each UIKit element, which is intended exactly for UI tests. This can be done either in the code or you can set it in the storyboard or Xib file in the Identity Inspector of the respective view. Similarly, in SwiftUI there is the modifier .accessibility(identifier:).

If you now give the button the accessibilityIdentifier "Example.Button", it can be accessed in the UI test via this string.

let button = app.buttons["Example.Button"]

In order to test certain conditions, one uses, as in unit tests, the assertions, which XCTest offers. To ensure that the button can be pressed, you can proceed as follows:

XCTAssertTrue(button.isEnabled)

The last step of our first UI test is to check that the button can no longer be pressed after deactivating the switch. For this purpose, the switch is read on the basis of its assigned accessibilityIdentifier and pressed once. Finally, we check whether the button is no longer active.

let uiSwitch = app.switches["Example.Switch"]
uiSwitch.tap()
XCTAssertFalse(button.isEnabled)

Xcode also offers the possibility to record certain interactions that are to be tested. This means you can interact with UI elements in the simulator and the recorder translates this into code for a UI test. In most cases not very reliable and the code is usually more complicated than necessary, but it can serve as an entry point. A recording can be started via the red record button below the editor when the cursor is in a test method.

Alerts and Navigation Bar

After completing the first UI test, we can follow the same pattern for our other two scenarios.

To test that the button triggers an alert, it is read again and finally pressed via the tap() method. An alert can be read by its title, but you can also use the element property, which can always be used if there is only one element of the corresponding type. For example, if there is only one button on the screen you could also use app.buttons.element to access the button. Similarly, the firstElement property will return the first matching element, for example, if it doesn't matter which concrete element of the type is needed.

Now we can use the exists property to make sure that the alert is really displayed and finally close it via the OK button. This is how the whole thing looks like in the end:

let app = XCUIApplication()
app.launch()

let button = app.buttons["Example.Button"]
button.tap()

let alert = app.alerts.element
XCTAssertTrue(alert.exists)
alert.buttons["OK"].tap()

The last UI test is to ensure that the text entered in the text field is displayed in the navigation bar after confirmation. Text fields can also be read out via the app variable. When entering the text there are a few things to keep in mind. First, the text field must be given focus by selecting it with tap(). After that enter any string with the typeText() function. In order for the text to be written to the navigation bar, we have to press the Return button of the keyboard. At this point, it is extremely important in the UI test to have the Software Keyboard in the simulator (I/O -> Keyboard -> Toggle Software Keyboard), otherwise the return button cannot be found.

Finally, the Navigation Bar can also be read out via its title, whereupon it is checked whether it is actually present.

let app = XCUIApplication()
app.launch()

let textField = app.textFields["Example.TextField"]
textField.tap()
textField.typeText("Good Morning")
app.keyboards.buttons["Return"].tap()

let navigationBar = app.navigationBars["Good Morning"]
XCTAssertTrue(navigationBar.exists)

Stumbling blocks

An important point to consider in UI testing is flakiness. A test is said to be flaky when sometimes it passes successfully but other times it doesn't. There can be many reasons for this. One reason can be that a state from a previous test was not reset and the app is not in the correct state, so for example, an onboarding screen that is only displayed the first time the app is launched is not displayed the 2nd time the UI test is run.

A common way to avoid this is to use launch arguments. These can be given to the app before launch in the UI test and read out in the app's code. For example, this way we can define that we want to reset the app on every run:

let app = XCUIApplication()
app.launchArguments = ["reset-app"]
app.launch()

In AppDelegate or SceneDelegate it can be checked if the reset argument is present and if necessary the database or UserDefaults can be reset, depending on the app scenario.

if CommandLine.arguments.contains("reset-app") {
resetApp()
}

In contrast to unit tests, where network calls are usually not actually executed, they are executed normally in UI tests. However, this can also lead to elements that are only displayed after loading the data from the server, for example, not being directly available in the UI test.

If a button is only displayed after a request to the server has been successfully executed, this can be taken into account in the UI test by means of a delay. A timeout can be defined via the waitForExistence method, which basically states that the duration of the timeout is waiting for the element to exist. Only if the condition is not fulfilled after the timeout, the test is considered as failed.

XCTAssertTrue(timelineCell.waitForExistence(timeout: 2))

Launch Arguments and the waitForExistence method are very useful to ensure that UI tests are deterministic. Only when every run of the test leads to the same result is it really useful.

Wrapping Up

As has been shown, UI tests are a very helpful means of ensuring the quality of an app. On the one hand, certain workflows can be tested, but it can also be ensured that the UI looks good on a wide range of device sizes. In addition, basically every interaction and gesture of the user can be mapped. Only WebViews or scenarios in which the device's sensors are accessed are less suitable.

Since it takes more effort to write and execute UI tests than e.g. unit tests, you should develop a certain feeling for where it makes sense to use them.

References

More articles from our blog

let’s dev Blog | Smart Prognosis of Energy with Allocation of Resources

Corporate

Smart Prognosis of Energy with Allocation of Resources

by Karl

2021-02-18

Read more
let’s dev Blog | Dasoman - Data-Sovereignty-Manager

Corporate

Dasoman - Data-Sovereignty-Manager

by Karl

2021-01-11

Read more
let’s dev Blog | We look back on the past months - And wish all the best for the coming year 2021!

Corporate

We look back on the past months - And wish all the best for the coming year 2021!

by Julian

2020-12-17

Read more
let’s dev Blog | Adobe Max - Online for the first time

Corporate

Adobe Max - Online for the first time

by Julia

2020-10-29

Read more
let’s dev Blog | CAN2BLE

Technical

CAN2BLE

by Raphael

2020-09-24

Read more
let’s dev Blog | Mensch und Computer 2020 - Digital Change in the Flow of Time

Corporate

Mensch und Computer 2020 - Digital Change in the Flow of Time

by UX Team

2020-09-18

Read more
let’s dev Blog | Neumorphism – A new era of user interface design?

Technical

Neumorphism – A new era of user interface design?

by Julian

2020-08-13

Read more
let’s dev Blog | UX Research Part 3 - UX Methods

Technical

UX Research Part 3 - UX Methods

by Elena

2020-05-28

Read more
let’s dev Blog | UX Research Part 2 - What is UCD and what does User Research have to do with it?

Technical

UX Research Part 2 - What is UCD and what does User Research have to do with it?

by Elena

2020-04-23

Read more
let’s dev Blog | go-digital promotes establishment of home office workstations

Corporate

go-digital promotes establishment of home office workstations

by Karl

2020-03-19

Read more
let’s dev Blog | Google Passes - Card Management on Android Devices

Technical

Google Passes - Card Management on Android Devices

by Michelle

2020-03-12

Read more
let’s dev Blog | 100% code coverage in software testing - a reasonable goal?

Technical

100% code coverage in software testing - a reasonable goal?

by Raphael

2020-03-06

Read more
let’s dev Blog | Swift UI - Simple and fast implementation of user interfaces

Technical

Swift UI - Simple and fast implementation of user interfaces

by Tobias

2020-03-02

Read more
let’s dev Blog | In dialog with the business juniors - Exciting insights into business start-ups and digital transformation

Corporate

In dialog with the business juniors - Exciting insights into business start-ups and digital transformation

by Julian

2020-02-27

Read more
let’s dev Blog | Simplified testing of iOS push notifications in the simulator with Xcode 11.4

Technical

Simplified testing of iOS push notifications in the simulator with Xcode 11.4

by Manuel

2020-02-26

Read more
let’s dev Blog | National meeting of the consortium of the SPEAR research project at let's dev in Karlsruhe

Corporate

National meeting of the consortium of the SPEAR research project at let's dev in Karlsruhe

by Karl

2020-01-27

Read more
let’s dev Blog | UX Research Part 1 - Why User Research is so important

Technical

UX Research Part 1 - Why User Research is so important

by Elena

2020-01-23

Read more
let’s dev Blog | Dark Mode

Technical

Dark Mode

by Elisa

2020-01-09

Read more
let’s dev Blog | We wish you a Merry Christmas - And a Happy New Year!

Corporate

We wish you a Merry Christmas - And a Happy New Year!

by Julian

2019-12-20

Read more
let’s dev Blog | Exchange on the topic of digitization with the Business Club Luxembourg at the Embassy of Luxembourg in Berlin

Corporate

Exchange on the topic of digitization with the Business Club Luxembourg at the Embassy of Luxembourg in Berlin

by Karl

2019-12-17

Read more
let’s dev Blog | DaSoMan at the Internet+ Expo in Foshan (China)

Corporate

DaSoMan at the Internet+ Expo in Foshan (China)

by Karl

2019-12-13

Read more
let’s dev Blog | Google Play Console: Pre-Launch Reports

Technical

Google Play Console: Pre-Launch Reports

by Fabian

2019-12-11

Read more
let’s dev Blog | DevFest 2019 in Hamburg

Technical

DevFest 2019 in Hamburg

by Julian

2019-12-05

Read more
let’s dev Blog | Vernissage digital art in the media theater of the Humboldt University Berlin

Corporate

Vernissage digital art in the media theater of the Humboldt University Berlin

by Karl

2019-11-21

Read more
let’s dev Blog | World Usability Day 2019 in Karlsruhe - let's dev supports as main sponsor

Corporate

World Usability Day 2019 in Karlsruhe - let's dev supports as main sponsor

by Aileen

2019-11-11

Read more
let’s dev Blog | Gutted - Open Day at the Alter Schlachthof Karlsruhe 2019

Corporate

Gutted - Open Day at the Alter Schlachthof Karlsruhe 2019

by Julian

2019-09-26

Read more
let’s dev Blog | Mensch und Computer 2019 - Conference on User Experience and Usability in Hamburg

Corporate

Mensch und Computer 2019 - Conference on User Experience and Usability in Hamburg

by Elena

2019-09-17

Read more
let’s dev Blog | Business and Enterprise App Distribution on iOS

Technical

Business and Enterprise App Distribution on iOS

by Aileen

2019-08-05

Read more
let’s dev Blog | Digital Transformation - Chances and Challenges in the Automotive Industry, Agriculture and New Technologies

Corporate

Digital Transformation - Chances and Challenges in the Automotive Industry, Agriculture and New Technologies

by Karl

2019-07-17

Read more
let’s dev Blog | let's dev supports runners at the 7th KIT Championship

Corporate

let's dev supports runners at the 7th KIT Championship

by Karl

2019-07-05

Read more
let’s dev Blog | Automated testing of C++ code with Google Test and Google Mock - Part 2

Technical

Automated testing of C++ code with Google Test and Google Mock - Part 2

by Arne

2019-06-13

Read more
let’s dev Blog | Apple WWDC 2019: These are the highlights of the keynote

Technical

Apple WWDC 2019: These are the highlights of the keynote

by Nicolas

2019-06-05

Read more
let’s dev Blog | App Builders 2019

Technical

App Builders 2019

by Nicolas

2019-05-23

Read more
let’s dev Blog | Official opening of the Consolidation and Expansion Center (FUX)

Corporate

Official opening of the Consolidation and Expansion Center (FUX)

by Helena

2019-04-15

Read more
let’s dev Blog | Delegation from Nottingham to visit the Alter Schlachthof in Karlsruhe

Corporate

Delegation from Nottingham to visit the Alter Schlachthof in Karlsruhe

by Helena

2019-04-14

Read more
let’s dev Blog | The time has come: We are moving!

Corporate

The time has come: We are moving!

by Helena

2019-03-26

Read more
let’s dev Blog | Automated testing of C++ code with frameworks - part 1

Technical

Automated testing of C++ code with frameworks - part 1

by Arne

2019-02-20

Read more
let’s dev Blog | The app in the Google Play Store

Technical

The app in the Google Play Store

by Elisa

2019-01-24

Read more
let’s dev Blog | „UX Day“ 2018

Corporate

„UX Day“ 2018

by Aileen

2018-12-17

Read more
let’s dev Blog | let's dev supports SG Siemens volleyball players from Karlsruhe

Corporate

let's dev supports SG Siemens volleyball players from Karlsruhe

by Helena

2018-12-04

Read more
let’s dev Blog | SMEs shape digitalization - SME Conference 2018

Corporate

SMEs shape digitalization - SME Conference 2018

by Helena

2018-11-12

Read more
let’s dev Blog | Apple Wallet

Technical

Apple Wallet

by Maik

2018-10-26

Read more
let’s dev Blog | „Mensch und Computer“ 2018

Corporate

„Mensch und Computer“ 2018

by Judith

2018-09-24

Read more
let’s dev Blog | State Design Pattern in Android

Technical

State Design Pattern in Android

by Thomas

2018-09-17

Read more
let’s dev Blog | let's dev is an authorized consulting company in the „go-digital“ funding program

Corporate

let's dev is an authorized consulting company in the „go-digital“ funding program

by Helena

2018-09-01

Read more
let’s dev Blog | App Design & Development Conference 2018

Corporate

App Design & Development Conference 2018

by Helena

2018-08-14

Read more
let’s dev Blog | iOS 12: The top new features at a glance

Technical

iOS 12: The top new features at a glance

by Nicolas

2018-07-17

Read more
let’s dev Blog | let's dev at CEBIT

Corporate

let's dev at CEBIT

by Karl

2018-06-11

Read more
let’s dev Blog | Introduction to User Interface (UI) Testing with Espresso

Technical

Introduction to User Interface (UI) Testing with Espresso

by Raphael

2018-06-07

Read more
let’s dev Blog | The app in the Apple App Store: what information is needed?

Technical

The app in the Apple App Store: what information is needed?

by Aileen

2018-04-27

Read more
let’s dev Blog | Smart Pointer in C++

Technical

Smart Pointer in C++

by Matthias

2018-04-01

Read more
let’s dev Blog | User interface design for iPhone X: all innovations at a glance

Technical

User interface design for iPhone X: all innovations at a glance

by Helena

2018-02-07

Read more
let’s dev Blog | WebVR - Virtual Reality Experience in the Browser with the A-Frame Framework

Technical

WebVR - Virtual Reality Experience in the Browser with the A-Frame Framework

by Judith

2018-01-10

Read more
let’s dev Blog | Deutsche Bahn Open Data Hackathon

Corporate

Deutsche Bahn Open Data Hackathon

by Karl

2015-03-31

Read more
let’s dev Blog | Blur effects under iOS 7

Technical

Blur effects under iOS 7

by Katja

2014-04-24

Read more
let’s dev Blog | Beyond App Store - iOS application distribution

Technical

Beyond App Store - iOS application distribution

by Karl

2012-08-27

Read more
let’s dev Blog | Front-end architecture - Model View Presenter and Message Bus

Technical

Front-end architecture - Model View Presenter and Message Bus

by Karl

2011-03-08

Read more