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?
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()
}
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With