Effective XCode UI Testing

UI testing is a great way to ensure that your UI interactions keep working as you’re adding new features or refactoring your app’s codebase –  it keeps your app functional.

Writing and running UI tests is kind of different from doing unit testing. You are actually interacting with your app rather than performing tests against a certain API. UI tests are often implemented as blackbox tests and you don’t even have to know the codebase. In Xcode UI tests run in its own App and they use two core technologies:  XCTest framework and Accessibility.

 XCode UI testing  has been around for a few years, but was unstable, flaky and hard to use – but things are getting better now. However there are still some issues. In this post I want to show some patterns how you can improve your UI tests.

Resetting your app’s State

As mentioned before, our UI tests will be running in an entirely different process, so we have zero access to our own code, which is very much by design.

However each App contains state that is stored in UserDefaults or even Core Data. For our UI tests we want this state to be at a defined state before they start. So it is important our App knows when it is started in UI testing mode and can reset it’s state.

Therefore we provide a launch argument when we start your App  in testing mode and check for this argument in the App delegate didFinishLaunchingWithOptions method.


func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]?) -> Bool {

    if CommandLine.arguments.contains("--uitesting") {
        resetState()
    }

    // ...Finish setting up your app

    return true
}

And our UI test class looks like this:


class MyUITest: XCTestCase {
    var app: XCUIApplication!

    override func setUp() {
        super.setUp()

        // Since UI tests are more expensive to run, it's
        // usually a good idea to exit if a failure was encountered
        continueAfterFailure = false

        app = XCUIApplication()

        // We send a command line argument to our app,
        // to enable it to reset its state
        app.launchArguments.append("--uitesting")
    }

    // ... your testing methods

}

Speedup Animations

Real time animations are central for human testers. However animations are not important for automated UI testing – in fact they are even time and CPU intensive. Therefore we often want to turn off animations for automated UI testing. Luckily this can be done by simply increasing the speed of Core Animation itself. And the best part: This is not even private API!

UIApplication.sharedApplication.keyWindow.layer.speed = 100;

This can be done in a central ViewController where the keyWindow is already initialized. Note: Do not call this code in the app delegate because the keyWindow is not initialized yet.

Speedup of animations can reduce testing time up to 10%.

tomkausch

Leave a Reply

Your email address will not be published. Required fields are marked *