Passing launch arguments to your app

To switch the loading of questions from the network to a local file for testing, you can pass your app a launch argument. This launch argument is then read by the app to make sure it loads questions from the JSON file like you did before in the unit tests rather than attempting to load trivia questions from the server.

To prepare for the launch argument and loading the JSON file, make sure you add it to the test target, the app target, and the UI test target. You won't need it in the UI test target just yet, but you will later, so you might as well add it to the UI test target while you're at it.

In order to pass launch arguments to the app, the setUp() method in the UI Test class should be modified:

override func setUp() {
  super.setUp()

  continueAfterFailure = false

  let app = XCUIApplication()
  app.launchArguments.append("isUITesting")
  app.launch()
}

The XCUIApplication instance that represents the app has a launchArguments property, which is an array of strings. You can add strings to this array before launching the app. These strings can then be extracting inside of the app. Modify the loadTriviaQuestions(callback:) method in TriviaAPI.swift as shown in the following code snippet:

func loadTriviaQuestions(callback: @escaping QuestionsFetchedCallback) {
  if ProcessInfo.processInfo.arguments.contains("isUITesting") {
    loadQuestionsFromFile(callback: callback)
    return
  }

  // existing implementation...
}

The preceding code should be inserted above the existing implementation of this method. The snippet checks whether we're UI testing by reading the app's launch arguments. If the UI testing argument is present, we call the loadQuestionsFromFile(callback:) method to load the questions from the JSON file instead of loading it from the network.

Note that it's not ideal to perform checks such as the preceding one in your production code. It's often better to wrap configuration such as this in a struct that can be modified easily. You can then use this struct throughout your app instead of directly accessing process info throughout your app. An example of such a configuration could look like this:

struct AppConfig {
  var isUITesting: Bool {
    ProcessInfo.processInfo.arguments.contains("isUITesting")
  }
}

We won't use this configuration class in this app since it's not needed for an app this small. But for your own apps, you might want to implement a configuration object regardless of app size since it leads to more maintainable code in the long run.

If you build the app right now, you should get a compiler error because loadQuestionsFromFile(callback:) is not implemented in the API class yet. Add the following implementation for this method:

func loadQuestionsFromFile(callback: @escaping QuestionsFetchedCallback) {
  guard let filename = Bundle.main.path(forResource: "TriviaQuestions", ofType: "json"),
    let triviaString = try? String(contentsOfFile: filename),
    let triviaData = triviaString.data(using: .utf8)
    else { return }

  callback(triviaData)
}

It's very similar to the question-loading method in the unit tests; the only difference is that it uses a different way to obtain the bundle from which the questions are loaded.

If you run your UI tests now, they will fail. The reason for this is that when the test framework starts looking for the elements it tapped before, they don't exist. This results in a test failure because the test can't tap elements that don't exist.

The test should be adjusted a bit because tapping a loader isn't very useful anyway. It's a lot more useful to make sure that buttons can be tapped and whether the UI updates accordingly. To do this, you can write a UI test that waits for the question and buttons to appear, taps them, and checks whether the UI has updated accordingly. The dummy data will be loaded in this test as well to verify that the correct question is shown and the buttons behave as they should.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset