Advances in Testing With Xcode 7 and Swift 2

In the early days of iOS, tools to facilitate testing were not a major focus of Apple's Developer Tools team. This has gradually changed over the years with the introduction of the XCTest framework and, more recently, support for asynchronous and performance testing.

With Xcode 7 and Swift 2, Apple is taking another big leap to improve testing in Xcode. In this tutorial, I'm going to walk you through three significant additions that will make testing easier and more enjoyable.

1. Access Control

In Swift 1, developers have to jump through a number of hoops to test their code. For example, a unit test target only has access to public entities of another module. This is not surprising if you're familiar with Swift's access control. Testing internal routines, however, becomes a pain.

Apple's Swift team was aware of this problem and, as a result, Swift 2 introduces the @testable attribute to make testing less painful. With the @testable attribute, the unit test target has access to every internal entity of another module. The following code snippet shows how to use the @testable attribute.

Let's create a simple project to see how it works. Open Xcode 7, create a project based on the Single View Application template, and tick the checkbox labeled Include Unit Tests.

Setting up a project with unit tests included

To show how the @testable attribute works, I've implemented a structure named User. It has two stored properties, firstName and lastName, and a private computed property, fullName.

Because we didn't specify an access level for the fullName computed property, it's access level is internal. If we want to unit test fullName, we could mark it as public. This isn't great and it defeats the purpose of Swift's access control.

Fortunately, Swift 2 solves this issue with the @testable attribute. The following code snippet shows how the @testable attribute is used. By prefixing the import statement with the @testable attribute, we can access the fullName property of the User structure in the testFullName method.

Note that the documentation clearly states that the @testable attribute can only do its job if the product is compiled with testing enabled. In other words, you can't and shouldn't use the @testable attribute for purposes other than testing.

2. Code Coverage

If you're testing the code you write, then you're on the right track. However, it's equally important to understand how well the tests you write cover the code you think they cover. While previous versions of Xcode have had support for code coverage to some extent, it has always been a bit finicky to get it to work. That's no longer the case with Xcode 7.

Instead of showing you a bunch of screenshots, I'd like to walk you through the steps involved to enable code coverage in an Xcode project. Let's take the project we created a few minutes ago as an example.

To enable code coverage, we only need to edit the active scheme. Click the scheme in the top left and choose Edit Scheme....

Edit the current scheme to enable code coverage

To enable code coverage, select Test from the left and tick the checkbox labeled Gather Code Coverage. That's it. If you've tried to enable code coverage in earlier versions of Xcode, then I'm sure you're happy to see how easy it is to enable code coverage in Xcode 7.

Tell Xcode to gather coverage dadta

Run the unit tests by pressing Command-U or selecting Test from Xcode's Product menu. When the tests have finished running, open the Report Navigator on the right and select the Coverage tab at the top. This shows you how well your unit tests cover the code you've written.

Code coverage in Xcode 7

It looks like we've done a pretty good job unit testing the User structure. It gets better though. Do you see the tiny arrow following the method name? If you click it, Xcode will take you to the source code the unit test tested. Because Xcode has collected coverage data, it can also show that coverage data in the source code editor.

The coverage data is shown on the right of the source code editor. The number in the gutter on the right indicates how often the unit tests have triggered that specific routine.

Code coverage in the source code editor

Code that wasn't executed during the tests are highlighted. This is very useful for writing better tests and for improving the code coverage of your test suites.

3. UI Testing

One of the most anticipated features of Xcode 7 is the integration of user interface testing. In the past, I've worked with KIF and UI Automation, but I've never been quite happy with either solution. Xcode's UI testing looks like the solution many of us have been waiting for.

XCTest Framework

User interface testing in Xcode 7 expands on Apple's robust XCTest framework through the addition of three classes, XCUIApplication, XCUIElement, and XCUIElementQuery. To make the creation of user interface tests easier, Xcode 7 provides the ability to record tests. This is a very powerful feature that some of you may already be familiar with if you've ever worked with Apple's UI Automation.

As with UI Automation, Xcode's user interface testing relies heavily on accessibility. It's therefore more important than ever to spend time making your applications more accessible to users with a disability.

Creating UI tests is a breeze

Note that UI testing is only available on iOS 9 and OS X 10.11. Apple emphasizes that unit tests and user interace tests complement each other. In other words, it's not a matter of choosing one or the other.

While it's easy to create user interace tests for an application, you are not expected to write UI tests for every possible scenario or use case. Start by focusing on common and critical use cases, such as user onboarding.

Test Reports

Test reports have also improved substantially. What I like most about the new tests reports is the addition of screenshots for failed UI tests. In addition to an error message, Xcode takes a snapshot of your application's user interface when a UI test fails. This makes it very easy to find and fix the problem.

Learn More in Our Testing With Swift Course

If you want to learn more about testing with Swift and the XCTest framework, then I encourage you to take a look at Derek Jensen's course about unit testing with Swift and XCTest.

Conclusion

Apple has put a lot of effort into improving testing and debugging with the release of Xcode 7. While integrated code coverage is fantastic, the addition of user interface testing is going to have an even bigger impact.

I hope this brief overview has whet your appetite for testing in Xcode 7. We will be covering these new features in more detail in future tutorials.

Tags:

Comments

Related Articles