XCUIApplication - You're probably doing it wrong

There are quite a few blog posts around the inter webs about the new iOS UI testing and how to do it. Most of them make multiple calls to XCUIApplication(). For example:

XCUIApplication().launch()  
XCTAssertEqual("Hello", XCUIApplication().staticTexts.element.title)  

In most cases this code, even though technically incorrect, will work fine. However in some cases it won't. The problem stems from the multiple calls to XCUIApplication().

The people who have written this code seem to assume that XCUIApplication() is accessing a singleton. Therefore multiple calls to it are fine. However, after a bug report to Apple I was told that it is actually creating a new instance of the application each time. Now because this application is used for communicating with the currently running app, it's ok is most cases if there are multiple instances.

But here's one where it isn't:

XCUIApplication().launchArguments = ["abc"]  
XCUIApplication().launch()  

Obvious now you think about it. But the launchArgument is being set on one instance and the simulator is being launched by another. So the argument will never be passed to it. Here's how the code should have looked:

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

To be far, Apple's doco on UI testing is pretty light. But the best recommendation I can give is to create an abstract test case class and set a local app variable. Like this:

class AbstractTestCase : XCTestCase {

    var app:XCUIApplication!
    override fun setUp() {
        super.setUp()
        app = XCUIApplication()
    }
}

Now all you do is use app everywhere you need it.


Comments powered by Disqus