Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode UI testing - login/logout with stored credentials

I want to run functional (UI) tests for the login procedure in my iOS app (Xcode 7.2.1).

The app's behaviour is that upon successful login, user credentials are stored in order to automatically login (without showing the login screen) in the next launches.

So I set up a sequence of UI events in the login screen to make the login test pass on the first time the app launches in the iOS Simulator. However, next times I run my tests will fail, since the login screen doesn't even show up as expected.

I see two options here, none of them seem to fit well:

  1. Reset iOS Simulator's content and settings with a script before each time my tests run. I tried adding a Run Script phase in the test target's Build Phases with: xcrun simctl shutdown booted && xcrun simctl erase all && killall "Simulator", and it doesn't seem to work (Simulator app doesn't launch and tests get stuck).
  2. Include in the -(void)tearDown some code to clear the stored user credentials. This option is not good either as not only it's run between each test method (not per test launch), but also it seems like I don't have access to the AuthManager class that I use to clear user's credentials.

What do you do when UI-testing login procedures like that?

like image 872
mllm Avatar asked Mar 14 '16 14:03

mllm


2 Answers

I've ran into the same types of issues. After a bunch of bashing around my best approach was to try and keep things a little more simple. In my tear downs I always "unwind" anything that I might have done. Some times it's overkill but it's still good practice. I've found many bugs while unwinding where I might have overlooked them if I did some sort of hard reset. IE: I'll navigate back to the home page (my starting point) and if I've signed in then I'll simply just sign out. For the record, on the app side when a users signs out, their credentials are stripped.

So for example, on my SignInTests.swift classes I put all my methods in an extension in the same class file. That way I can simply call SignInTests().signIn() or SignInTests().signOut() so that I can access them from whatever other test class I might to called signOut() from.

This is my scenario that works perfectly for me. May not be the best option for you but I hope it points you in the right direction.

like image 61
Craig Fisher Avatar answered Sep 20 '22 11:09

Craig Fisher


When you run your application from XCTestCase you could use something like this

let app = XCUIApplication()
app.launchArguments.append("--uitesting")
app.launch()

And in AppDelegate method

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

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

Run this in first test when you need to login. In next test you could clear data from launchArguments.

app.launchArguments = []
like image 44
Arek Avatar answered Sep 21 '22 11:09

Arek