Write your first Unit Test in Swift

Login to Access Code

Unlike the Ruby community, the Objective-C and Swift world have very much lacked the abundance of resources and tutorials in teaching TDD or even just tests in general. Hell even a brand-spanking-new project created by Xcode doesn’t come with a practical, real world test in it.

Thus this post will focus on being the most absolute, basic way to get started with tests. If you have ever run a custom test that actually tested your application code, then stop reading and move on to a different article. On the other hand, if you have never written a test in Xcode or you do not know how to test your application code, then keep reading, because I’m going to explain it all in great detail.

A quick primer on iOS testing

As of Xcode 6 Beta 4, access modifiers were introduced which control the visibility and access of a class and it’s properties to other modules. This helps with name collision and creates a stricter thought process when architecting your code rather than simply having a global-everything-is-public issue. These access modifiers are:

  • private - file level access
  • internal - module level access
  • public - available between modules

While great to have, these access modifiers weren’t introduced day 1, thus tests have changed from then to now (everything was basically public before). Why does this matter? Well when testing, you are building for a different target which essentially like building for a different module for your application. The Unit Tests (by default) only run within the Test target, while your application code (again by default) only runs in your application target. Let’s create a new project to walk through this issue.

Creating an application and test

I’m creating a new, Single View iOS Application, any name or identifier will do. This boilerplate app comes with an AppDelegate, ViewController and a single Unit Test, which we can see on the left, with two build targets which we can see on the right. In the screenshot, you should see that we selected both the Application and the ApplicationTest as targets, which we’ll get to in a minute (by default, you will only see the Application target selected).

Setting Target Membership for Tests

If you look at your one and only test in the Tests folder, you can see some code for setup and teardown, and a single assertion which evaluates that true == true. This doesn’t do much for us, so let’s write a simple test that checks to see that our ViewController loaded with a view property when the app runs. Think of this as a Hello World of Swift testing. I am going to gut the setup and teardown as they are not very relevant for this type of basic test, but you could just copy in the testViewDidLoad() into your Test class.

import UIKit
import XCTest

// Our Project Module
import Unit_Test_Example

class Unit_Test_ExampleTests: XCTestCase
{
  // we can't do much  without a view on our root View Controller
  func testViewDidLoad()
  {
    // we only have access to this if we import our project above
    let v = ViewController()

    // assert that the ViewController.view is not nil
    XCTAssertNotNil(v.view, "View Did Not load")
  }
}

Note that I first had to import our project at the top. Your test code and your application code are essentially two different modules, and have internal access by default, so they are not aware of each other’s classes. This will become apparent when you try and run this test (from the top menu: Product > Test or with keyboard shortcut: cmd+u

XCTest Fails in Swift

You should get an error at this point: Use of unresolved identifier 'ViewController' which is basically letting you know that your test doesn’t know what the ViewController class is. We can solve this one of two ways:

  1. Make our class and it’s methods public
  2. Add our class to the Test target

In almost all cases, you should probably opt for adding your application code to the Test target. Simply select the file in the file explorer on the left, and select your Test target under Target Membership on the right.

Now you can run your test and your assertion that the ViewController.view property is not nil. Woot! If you made it this far, you can now start writing code. I urge you to go TDD wherever possible. Define your properties and methods in the form of a test first, have them fail, and then write the application code that allows them to pass.

Happy coding!