Local API Call Tutorial with WireMock and UI Tests in Xcode

Learn how to use WireMock, a tool you can use in conjunction with User Interface tests to provide a local copy of remote API call results. By Mark Struzinski.

Leave a rating/review
Download materials
Save for later
Share

WireMock is a development tool that provides a local copy of the results of a remote API call. You can use it in conjunction with User Interface (UI) tests to render different types of API responses.

UI testing acts as a safety net, ensuring you’re delivering the intended user experience. It focuses on the end-to-end experience of your app. As well, UI testing can answer different questions than unit testing can, such as:

  • What happens on this screen if my view is empty?
  • What happens if I get an error from a network request?
  • Does my validation UI show the correct information for different kinds of input?
  • Do my table cells reflect the data received?

Getting Started

First, locate the Download Materials button at the top or bottom of this tutorial. Download the starter project and open it. Build and run the project to check out the functionality.

The Star Wars Info app uses the Star Wars API to retrieve a list of Star Wars characters. You can tap each cell to navigate to a detail screen for that character.

Sample App

Running the Tests

The app is already set up with a UI testing target and two UI tests. The UI test target is already connected to the default Test action of the build scheme.

Run the tests by pressing Command-U or by clicking the menu item Product ▸ Test. You’ll see the app launch and navigate from the list view to the detail view and back. During this navigation, the UI tests are validating expected conditions on both the list and detail views.

To see the test report, go to the Report navigator in the left pane and view the test results:

As long as your computer is online and the tests can successfully hit the Star Wars API, the tests will pass.

UI Test Code

Look in StarWarsInfoUITests.swift to see the UI tests. The details of UI testing are beyond the scope of this article. Please see iOS Unit Testing and UI Testing Tutorial for a deep dive on that topic!

The sample project demonstrates best practices, including:

  • Use accessibility identifiers, not accessibility labels, to identify elements whenever possible. Benefits to this approach include:
    • Accessibility identifiers are not available to the user in any way, so you can name them whatever you want.
    • Identifiers remain constant. For example, a label may have different values but its identifier remains constant. So your tests will still be able to find the element on the screen.
  • A convenience method named waitForElementToAppear(_:file:line:elementName:timeout:) in an extension on XCTestCase allows for custom timeouts.
  • Passing the file and line numbers to convenience functions allows the UI testing system to report test failures at the call site.
  • Accessibility identifiers are not available to the user in any way, so you can name them whatever you want.
  • Identifiers remain constant. For example, a label may have different values but its identifier remains constant. So your tests will still be able to find the element on the screen.

Challenges With the Current Setup

This small app and the associated tests perform well in the current configuration, but as the code base grows, the app will rely on many more network requests. Tests will slow down and become flaky.

Here are some issues you can anticipate as the code base grows:

  • What happens if the network request you’re relying on fails?
  • What happens if the network slows down, causing timeouts or extended wait times?
  • What if the list request begins sending data back in a different sort order?

In all three scenarios, your tests would fail. There’s one common denominator. None of these test failures would be due to a programming error or logic issue. Test failures in these scenarios would be false positives, because the failure would be out of your control.

Mitigating Network Failures

In this tutorial, you’ll eliminate one of the sources of uncertainty in UI testing. You’re going to stop making live network requests and rely on a network mocking technology called WireMock. WireMock allows you to eliminate the network as a potential source of failure in UI tests.

Using WireMock, you’ll always get the same response for a given request on every test run. This allows you to have more confidence in your tests. If there’s a failure, you’ll spend less time trying to determine why. The network is one of the more volatile components in any application. By taking it out of the list of potential reasons for failure, you’ll be able to focus on the base functionality you’re trying to test with each screen.

Overview of WireMock

WireMock is an open source library that allows you to run a local web server for testing. By updating the API endpoints you’re calling from your app while running a test, you can return known responses. This can help you to move faster during development. During a test run, pointing your app at a WireMock instance allows you to receive expected responses from API requests.

Enough of the theory. Time to get started!

Setting Up WireMock

WireMock requires at least Java 7, so make sure your Mac has an updated version of Java installed. Download the latest Java Development Kit, JDK from Oracle. You’ll be running WireMock as a standalone instance. Go to the download page and get the latest stable build of WireMock. The download will be a single JAR file.

Go to the base directory of the starter project, and create a directory named Vendor. Move the JAR file into this directory. Rename the JAR file WireMock.jar to make it easier to interact with from the command line. Next, open Terminal and navigate to the Vendor directory you created.

Inside this directory, type the following command to start the WireMock process:

java -jar wiremock.jar --port 9999 --verbose

This command starts WireMock on port 9999 and turns on verbose mode. Turning on verbose mode allows you to see all messages, including URL matches and near misses as your app interacts with the WireMock endpoints. This is a big help when trying to determine why a WireMock endpoint may not be working.

Now, test that WireMock is running on your system. Open a browser and go to http://localhost:9999/__admin/mappings.

You should see the following:

{
  "mappings" : [ ],
  "meta" : {
    "total" : 0
  }
}

Great! This means WireMock is up and running. You’ll also notice WireMock has created two directories inside Vendor: __files and mappings.

Files and Mappings Directories

By default, the standalone instance of WireMock looks for these two directories relative to the executable’s location.

  • The __files directory contains the mock responses you want to send back for any given API requests.
  • The mappings directory contains files that map API request patterns to specific files that contain the desired response.