UI Testing with XCUI

I'm trying for unit testing of view controllers in xCode 8. I'm able to record, assert and run it successfully using XCUI. But I want to test particular view controller independently.

Like there are 4 controllers A,B,C and D in sequence (A->B->C->D). I want to directly launch C controller and test it independently.

I'm able to test in this way i.e. default XCUIApplication will open A controller then click on something you will go to B Controller and then click on button in B will take you to C Controller. Then you can test it out. But I don't want in sequence. I want to directly test C controller.

Can you please help if anyone else has done same kind of job. Thanks in advance.

Hey, there are a few options to achieve this, though all would require some minor changes to your app.


1) Using XCUIApplication.launchEnvironment


// ScreenAUITests.swift
func testSomeFeature() {

   // launchEnvironment is a [String: String]
   // anything added here can be retrieved within the app being tested

   let app = XCUIApplication()
   app.launchEnvironment = ["screenToLaunch": "screenA"] // you can clean this up by using enums to define the keys
   app.launch()

   // test screenA
}


And then from within the app


// AppDelegate.swift
...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        let window = UIWindow(frame: UIScreen.main.bounds)
        window.rootViewController = createRootViewController()
        window.makeKeyAndVisible()

        self.window = window
        return true
}
...

// Can be extracted to a helper class if it gets more complex (e.g. if dependencies are needed etc...)
extension AppDelegate {
   func createRootViewController() -> UIViewController? {
        // remember to update the project settings so it no longer automatically loads the storyboard
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        var rootViewController = storyboard.instantiateInitialViewController()

        #if DEBUG
            // This is the basic idea, you can ofcourse clean this up by having some helper classes / enums etc...
            let environment = ProcessInfo.processInfo.environment
            if let screenToLaunch = environment["screenToLaunch"] {
                rootViewController = storyboard.instantiateViewController(withIdentifier: screenToLaunch)
            }
        #endif

        return rootViewController
   }
}



2) You can also use XCUIApplication.launchArguments which is very similar to the approach above, launch arguments however is a [String]


One cool thing you can do with LaunchArguments is, if you store values in the follow format


let app = XCUIApplication()
app.launchArguments = ["-someKey","someValue"] // note the '-' before the <key>


This would add to / override NSUserDefaults in the main app while its running!


// somwhere in the app
UserDefaults.standard.value(forKey: "someKey") // returns "someValue"



Using a combination of both these techniques you can start creating Mocks in the main app which your UI test can configure!


Hope this helps

UI Testing with XCUI
 
 
Q