Automated UI Testing in Swift & iOS

Testing applications is a critical component of development. As we iterate on our applications, we may change the UI in unintended ways. New designs may come in as a result of user feedback that means we need to change button colours, labels, etc. Manually testing these can be expensive and time-consuming. UI testing can automate this.

However, there’s an additional benefit that comes from UI testing, and it’s incredibly powerful: accessibility.


Improve Your App With This One Neat Trick

Accessibility refers to a number of features that come native to iOS devices. It allows individuals who may have an impairment use their device without issue. These features include things like VoiceOver, Dynamic Type, Assisted Touch, and various others.

VoiceOver allows users with a visual impairment to navigate through the app with relative ease. Why relative? Because often developers (me, included) can forget to develop with accessibility in mind. To initiate VoiceOver, visit Settings > General > Accessibility > VoiceOver and tap to enable it. After you’ve done this, visit an app (perhaps your own) and see how difficult — or easy — it might be for someone with a visual impairment to use it.

Dynamic Type allows users to increase or decrease the font size of their phone. Again, this helps users with a visual impairment to clearly see and read the content on the screen. This can also be enabled in the Accessibility section of the settings page.

With these accessibility settings enabled, the way in which a user interacts with your app will change. For example, with VoiceOver enabled a user would double tap to select an element, or trigger an action. Left and right swiping will move a user onto the next accessibility element in the hierarchy. Swiping up and down will move through the accessibility elements in the hierarchy and read the elements accessibility label. If you have some tap gestures or other gesture recognisers, it’s important to be aware of this crucial API in order to avoid interfering with interactions that a user expects to work in a certain way.

XCUITesting & Accessibility

So how do these two seemingly unrelated features relate? XCUITests hook into the accessibility elements of your application in order to read values, trigger actions, and check existence. If an element is not visible to the accessibility hierarchy, it won’t be visible to the Xcode UI test runner. In writing UI tests, you’ll inadvertently improve the accessibility of your app.

In rare cases, it can be hard to convey the value of writing any kind of test. Clients or Product Owners might not understand that tests prevent bugs and keep tech debt to a minimum, mostly because there’s no product at the end of it. A PO can’t interact with a unit or integration test. What a product owner can do, however, is inform stakeholders that as a result of spending time writing these tests, we’ve increased accessibility and, as such, our potential user base. Automated UI tests can reduce regression testing cycle times also, meaning the cost of manual testers is reduced as well.

I’ll be going into making your app more accessible in a future blog post, because it requires a full post of attention. For now, take a look at the official documentation here as a starter for ten.


Getting Started

Let’s begin with a scenario that I recently implemented in our project. A user visits a specific section of our app, and upon entering they’re presented with an onboarding walkthrough section. I wanted to ensure that should the strings be changed, we’d catch this change. Additionally, I wanted to ensure that when a user reaches the last screen the button changes text to “Finish” and on tapping it, the onboarding is dismissed. Pretty simple, but very familiar. For reasons of disclosure, I can’t show the actual app, but let’s see a similar example:

In order to get setup, you may need to add UI Testing to your targets. If you’re doing this for the first time, just click the following check box

However, if you’re adding UI tests retrospectively, head over to File > New > Target… and select iOS UI Testing Bundle. Now, edit you app’s scheme and make sure the bundle is enabled:


Writing Your First Test

OK, what’s going on in the example above? We launch the app, swipe left, ensure element values are changing, and terminate on completion. This depends on accessibility identifiers and values being set at the ViewController level:

DataViewController.swift

Crucially, we need the existence of the accessibilityIdentifier and the accessibilityValue. Now, in the tests we can do the following:

Let’s step through this. There’s two things we interact with here: XCUIElement and XCUIElementQuery. When we access otherElements we retrieve a XCUIElementQuery which allows us to subscript to find our view, and check it exists. Essentially we’re asking: is the view on the screen.

Some elements have dedicated types that we can access, i.e. buttons, cells and labels. In this instance, we’re accessing the label which contains the month text app.staticTexts. This returns an array of labels on the screen, and so we use the element(boundBy:)method to get the first in the hierarchy. If there was a button on screen, we’d be able to call the tap method. In a more complicated scenario, you can navigate away from the page, and return to it, ensuring that the app doesn’t show the onboarding again. That’s pretty powerful.


Rounding up

Of course, there are limitations to UI tests. They’re pretty time intensive, meaning that if you run them as part of your CI pipeline, you can probably expect delays. Ensure you keep these tests as simple as possible as well. Any complex logic should be saved for unit tests. These tests should be ensuring the app looks like it ought to, and the interactions perform as you’d expect.

Testing is really powerful, and provides you with an extra layer of confidence. I now know that the onboarding shows when it should, and I don’t need to manually verify this every time — my CI pipeline does that for me. Combine this with snapshot testing, and you can give your design team confidence that the app looks as they designed it. You can run it on multiple devices in a much quicker period than it would take you manually. Most importantly though, you’ll have made some steps towards making your app more accessible, and that’s a huge bonus!

I hope you enjoyed my first article!
Please comment below on any feedback, and hopefully, I’ll see you in the next one! You can catch me talking about all things mobile development on Twitter too.