I'm trying to get started on XCUITests for an iOS app my company currently develops. Also, I'm using Cucumberish to organize tests and use our already existing feature files.
Our app requires the user to login first thing before using any features, so I want to reset the app state between each test scenario to perform login again (Xcode reinstalls the app, but user data remains and the app becomes forever logged in after the first test). I've been trying a lot of different methods to accomplish this, but no luck so far.
Automating the Springboard to reinstall the app doesn't work (data isn't removed), I'm not able to call classes defined in the app using "@testable import" (so I could clear data programatically), there doesn't seem to be a way to call a shell command between tests to hard reset the simulator.
Do I have a choice? Or do I have to manually run through the UI to logout after each test case? (which for me sounds very unreliable - specially if tests fail)
Yes, there is a way to achieve this, I use it in my tests also.
You should talk to your app using launchArguments
(or eventually launchEnvironment
). First, in your setUp()
method, tell your app that it is in the UI-TESTING
mode:
override func setUp() {
super.setUp()
continueAfterFailure = true
app.launchArguments += ["UI-TESTING"]
}
Then, in every test where you expect logged out user, inform your app that it should logout before calling XCUIApplication.launch()
method:
let app = XCUIApplication()
func testWithLoggedOutUser() {
app.launchArguments += ["logout"]
app.launch()
// Continue with the test
}
Then, in your AppDelegate.swift
file, read the arguments and act accordingly:
class AppDelegate: UIResponder, UIApplicationDelegate {
static var isUiTestingEnabled: Bool {
get {
return ProcessInfo.processInfo.arguments.contains("UI-TESTING")
}
}
var shouldLogout: Bool {
get {
return ProcessInfo.processInfo.arguments.contains("logout")
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if AppDelegate.isUiTestingEnabled {
if shouldLogout {
// Call synchronous logout method from your app
// or delete user data here
}
}
}
}
I wrote a blog post about setting local state in the app, you can check it out here.