Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

launchArguments in UITesting in Xcode 7.3 not working

I've been writing UI tests in Xcode 7.3 and recently wanted to add a launch argument to enable some test code inside the app. I initially tried setting XCUIApplication().launchArguments as several people have done in various posts, but they would not work.

Digging around it appears that both launchArguments and launchEnvironment cannot be setup within a UI test, even though the API documentation says they can.

Further when I attempted to set launch arguments and environment variables in the UI Testing scheme, they also where not passed through to the app, where as when unit testing or running the app, they are.

Here's a copy of a quick tests I did to prove this, all these tests fail.

import XCTest

class LaunchDebugUITests: XCTestCase {

    func testLaunchArgumentsSetting() {
        XCUIApplication().launchArguments = ["abc"]
        print("Arguments \(XCUIApplication().launchArguments)")
        XCTAssertTrue(XCUIApplication().launchArguments.contains("abc"))
    }

    func testLaunchArgumentsAppending() {
        XCUIApplication().launchArguments.append("abc")
        print("Arguments \(XCUIApplication().launchArguments)")
        XCTAssertTrue(XCUIApplication().launchArguments.contains("abc"))
    }

    func testLaunchEnvironmentSetting() {
        XCUIApplication().launchEnvironment = ["abc":"def"]
        print("Environment \(XCUIApplication().launchEnvironment)")
        XCTAssertEqual("def", XCUIApplication().launchEnvironment["abc"])
    }

    func testLaunchEnvironmentAppending() {
        XCUIApplication().launchEnvironment["abc"] = "def"
        print("Environment \(XCUIApplication().launchEnvironment)")
        XCTAssertEqual("def", XCUIApplication().launchEnvironment["abc"])
    }

} 

Has anyone else encountered this? Do you have a work around?

like image 545
drekka Avatar asked Dec 02 '22 13:12

drekka


2 Answers

Apple got back to me and told me I was using XCUIApplication() incorrectly.

You should not invoke XCUIApplication() multiple times.

Many of the blogs I read did this call multiple times and is most circumstances it doesn't matter. In fact many blog posts treat the function like it's accessing a singleton. I had a feeling this was incorrect as it looked wrong, but I figured other people would have got it right.

But it isn't. It's not accessing a singleton and actually creates a new XCUIApplication instance each time it's called. Hence my code was failing because I was setting launch arguments on one instance, then creating another one to launch.

So my tests should have actually looked like this:

func testLaunchArgumentsSetting() {
    let app = XCUIApplication()
    app.launchArguments = ["abc"]
    print("Arguments \(app.launchArguments)")
    XCTAssertTrue(app.launchArguments.contains("abc"))
    app.launch()
}
like image 136
drekka Avatar answered Dec 05 '22 10:12

drekka


You need to also, then, launch you app and check in the app for the argument. Here's how I do it...

func testFooBar() {
    // given
    app.launchArguments = ["shouldDoBar", "shouldDoFoo"]

    // when
    app.launch()

    // then
}   

Then in your app

int main(int argc, char *argv[]) {
    NSArray *arguments = [[NSProcessInfo processInfo] arguments];

    if ([arguments containsObject:@"shouldDoBar"]) {
       doBar();
    }

    if ([arguments containsObject:@"shouldDoFoo"]) {
       doFoo();
    }
    ...
}

You might want the arguments checks somewhere more appropriate to your use (and perhaps also wrapped in a #ifdef DEBUG ... #endif to avoid shipping it).

like image 34
Michael Avatar answered Dec 05 '22 08:12

Michael