How to Test Your iOS App with Test Automation Frameworks
- 27842 views
- 10 min
- Dec 12, 2017
Whereas testing has become commonplace in traditional programming, mobile developers still tend to avoid it and, by doing so, miss out on ample opportunities. Mobile app testing helps you find mistakes such as security vulnerabilities, crashes, memory leaks, and incompatibilities.
Moreover, mobile app tests enable you to identify potential bottlenecks in an app’s logic. Statistically, testing reduces the number of bugs connected to pre-release builds by 40 to 90 percent.
We’ve decided to fight this injustice and devote an article to iOS app tests. In this article, we’ll spell out the testing process and introduce our favorite frameworks.
iOS testing: automated or manual?
iOS testing involves two distinct types of tests: manual tests and automated tests. Each has its advantages and disadvantages. In our work, we prefer to use automated iOS testing tools. Why? Because automated tests are executed by tools and\or scripts, so they’re faster and more reliable than manual tests.
To top it off, automated tests can run on multiple devices and different SDKs. This means that automated tests can boost your testing productivity, save time, and lower development costs.
There are two main types of automated tests for iOS: the unit tests and UI tests. Let’s take a closer look at each.
What’s iOS unit testing?
One of the most convenient ways to test source code is to check the correct operation of each module discretely. In this case, you need to break down your app’s code into separate parts in accordance with the basic rules of refactoring. We call this testing approach unit testing or module testing.
Unit testing makes development agile, improves the quality of code, and helps you detect software bugs in iOS apps at an early stage.
Obviously, mere source code testing isn’t enough for a comprehensive analysis of your app, however. This is why you need to examine the graphical user interface (GUI) as well.
What does UI testing mean?
Introduced in Xcode 7, UI testing enables you to examine a user’s interactions with separate elements of the graphical user interface and validate data that these elements may contain. UI testing helps you ensure that the UI functions correctly and meets specifications.
UI tests speed up the estimation process for QA teams and, as a consequence, improve your team’s efficiency.
I bet you’d like to know how to create UI and unit tests and what framework to use.
What iOS testing framework should I use?
You can write both unit and UI tests for iOS apps using the basic XCTest framework. XCTest provides a core set of features to check that an app is working efficiently. But if you want extended functionality, try one of the following frameworks:
- Quick and Nimble – This easy-to-use combination helps you create unit tests to check source code. Quick is a testing framework and Nimble is a matching framework.
- OHHTTPStubs – This framework lets you test HTTP requests by adding specially prepared response data. Additionally, OHHTTPStubs lets you change response time, code, and headers.
- KIF – Short for Keep IT Functional, KIF is one of the tools for UI testing of iOS apps that lets you test functional UI features.
These frameworks run on Objective-C as well as Swift and help you cover the whole project with tests and add extra functionality as necessary. In fact, you can easily apply these frameworks to a Model–View–Presenter (MVP) or Model–View–View-Model (MVVM) architecture.
Before using any of these automation frameworks, however, you’ll need to set up your iOS project.
How to set up an iOS project for testing
Let’s create an empty iOS project with one screen. Don’t forget to check the include unit tests checkbox. Then set up a framework. We recommend using Cocoapods. The podfile structure is quite simple:
Pay special attention to the distribution of targets, as they help keep projects in a state that’s convenient for testing. Keep in mind that the arrangement of targets depends on the type of project.
Finally, run the pod install command and wait for the framework to finish setting up. Congratulations! You’ve created a minimal project to demonstrate the feasibility of testing. Now it’s time to see some testing frameworks in action.
How does Quick/Nimble work?
Create a simple class called ContactRecord with two fields – name and phone number – in the main target. Specify the underlying type for these fields.Now go to the testing_demoTests.swift file in the testing target. Note that Xcode has already generated several standard methods. These methods allow you to execute the necessary test configuration at any time within the implementation and to measure the app’s performance.
Next, replace the code in the testing_demoTests.swift file with the following. Of course, you may use the standard functionality of the XCTest framework. But we recommend writing this code using Quick:
By doing this, you’ve added imports of two frameworks: Quick and Nimble. Keep in mind that Xcode may show an error, saying that framework data is absent. This happens because the testing target should be compiled. To do this, press CMD+U.
You’ve also added the import of the ios_demo target. This is necessary to make Xcode see classes in the main target.
Let’s turn now to the FirstTestSpec demo test. The FirstTestSpec and QuickSpec classes inherit from XCTestCase. This lets you use the new functionality along with standard methods, such as setUp().
Generally, we recommend breaking your tests into groups. To do so, use the describe function with a description of the test group and the closure/block where tests will be run. The it() function describes a specific test case. This function also contains a description and a block.
At this point, you’ve created an object of the ContactRecord class for simple testing. Now call for matchers, the value correspondence checking functions. These functions are part of the Quick and Nimble frameworks. Use them to check the type of fields and the default values of these fields:
Now press CMD+U and wait for the test to execute. If it executes successfully, Xcode will put a green checkmark next to the FirstTestSpec class. If it fails, a red X will appear.
At first, you’ll need Quick/Nimble’s two primary functions:
- expect - to
- expect - notTo
and subsequent checks:
- beAnInstanceOf (for objects)
- beAKindOf (for classes)
- beLessThan (and corresponding modifications)
- beTrue or beFalse
- beNil (for objects)
Additionally, Quick/Nimble gives you the opportunity to work with asynchronous expectations, which looks like this:
But what if your project deals with diverse exceptions? Don’t worry, you can also test it. Just check out this example:
This is how you can write automated tests with Quick/Nimble. But what about using OHHTTPStubs?
How does OHHTTPStubs work?
If an API doesn’t function properly, no one will adopt it no matter if it’s free, open source, or for cost. Without API testing, you can hardly examine all the possible ways that a user might interact with your app and its related sub-apps. What’s more, API bugs may not only crash a single app but may ruin a chain of business processes relying on it.
Testing API requests helps to debug tasks connected to the return of data from remote and local stores. Indeed, fairly often a response structure may contain invalid data. This may lead to unexpected and probably unpleasant outcomes. To avoid such problems, you need to test the network stack as well.
We advise checking the network stack with the OHHTTPStubs framework. Using OHHTTPStubs, developers can deal with NSUrlConnection and NSUrlSession (i.e. OHHTTPStubs main functionality).
Let’s use the Recipe Puppy API to explore how OHHTTPStubs works. First, create an ApiClient class that will send one simple request to the Recipe Puppy API and receive a list of recipes in return:
Once the request has been executed, you can check the result (e.g. the number of elements in the block or any other characteristics).
Let’s try to prepare a test response for the request. Here we need to create a stub, or a file with prepared data for testing. It’s good practice to write response templates and test with their help.
Once you’ve created the stub, you’ll get json from the puppy_response.json file instead of a response from the remote server. Therefore, you can add your own data to the test target in the project and examine how the app responds to this data.
Once you’ve executed the test, it’s recommended to delete the stubs from the app’s memory. You can do this inside the afterEach closure.
Note that you can also use beforeEach to configure a test before execution. These two functions allow you to control each test state before and after execution:
Now you already know some common iOS unit testing frameworks. Let’s now consider a UI testing framework.
How does KIF work?
Creating UI tests is almost the same as creating unit tests. But still, you need to be aware of several differences.
To write a UI test, you can use the standard system framework. However, there are some restrictions. For instance, the target of UI tests is isolated from the app target, so you won’t get full access to the main app target. Such isolation may pose problems with import of classes, which is especially critical for Swift.
To overcome this problem, you can use the KIF system framework. While testing controls, KIF offers a higher animation speed than XCUITest (the basic framework for UI tests) does. Moreover, KIF enables you to interact with objects from the main target.
All tests related to the graphical user interface are executed on the main thread. Start with adding a special extension to support Swift:
If you want to access directly an element (e.g. the red button), use the waitForView method:
In order to check the properties of any UI component, you can connect Nimble along with the expect function.
Then, create a simple test switching the colors of views and validate these colors. To do this, we need three UIButtons. Set an accessibility label in the interface builder for each of the buttons. After that, create a UITestSpec class and test the buttons. Using the accessibility label, you can perform the tap action on each button and compare each color’s component with the expect function.
We’ve decided to make it visual for you and record the color validation. See the video below.
You can also check out the full version of the demo app that we’ve developed to show the capabilities of mobile testing.
Although mobile app testing may slow down development, it’s an effective tool in the struggle for app quality. Mobile tests help you detect mistakes at an early stage, check the efficiency of your app, and enhance its functionality.
Moreover, mobile app testing is part of continuous integration, and you can always find open source automation frameworks to write your own automated tests.
Follow our Twitter account to keep up with the latest tutorials and articles on iOS development!