Unit Testing in Xcode 7 with Swift

Every iOS programmer has to debug their apps once in a while. Unless you’re some kind of crazy coding ninja, you know that desperate feeling when you have is to look for a bug in your code for hours and hours until you realize you made a simple syntax error. Or even worse, never finding the bugs. No matter if you are new to programming or have developed multiple apps, routinely writing unit tests will make your code more reliable, safer, and easier to debug!

Luckily for you, Xcode 7 and Swift support Unit Testing. Although Unit Testing doesn’t mean bug free apps, it’s still a very powerful way to verify that every piece or unit of code does its job and facilitate the process of debugging.

As the name implies, in Unit Testing you create small and specific functionality tests for a certain unit of code and make sure that every unit passes the tests. If it passes the test, a green logo will appear next to it. If, for any reason, it was not successful, Xcode will mark a test as ‘failed’. This is a sign for you to look into your code and search for the reason for failure.

A Brief Look at the Demo Project

First, download this starting project I created for you. It’s a simple app that will do a percentage calculation of a given number and a percentage. (For example: 10% of 80 is 8).

This PercentageCalculator project is rather simple. The only essential file for you to look at is ViewController.swift. The code is documented in comments and very straightforward.

It has 5 IBOutlets: one for every UIElement on screen, except for the title, and 2 IBActions for each of the two sliders. The name for each IBAction accurately explains what the method and action performs. When one of the two slider value changes, the value of either the percentage or number is changed.

Furthermore, it has two simple functions “updateLabels()” and “percentage()” that do exactly what you would expect them to do: the first one updates the labels when a slider is changed, the second one takes two floats and returns the percentage calculation.

Run the app in your simulator. At first, everything looks normal. But as soon as you start changing the numbers, you will notice that the result value is wrong. To find the bug, we can divide our code in units and test them separately to see if they do what is expected. This will not solve the bug, but narrow down where you have to search it.


When I created the project, I selected the option to include a test file by default. (If you want to add one manually, select File > New > File > Unit Test Case Class under iOS Source). In this case, the file was already created by Xcode and can be found in the “PercentageCalculatorTests” folder in the project navigator.


In PercentageCalculatorTests.swift there are 4 methods created for us in the PercentageCalculatorTests class. Two of them are example test methods that you can delete (you can recognise test methods because they start with the test keyword and have a diamond icon next to them in the gutter, & end with “…Example”). The other two, setUp() and tearDown() are special boilerplate methods in that they are called respectively before and after every test method is executed.

Let’s Begin to Write Unit Test

Now, it’s time to write your first unit test method! For this tutorial, we are only testing the ViewController class, we will need to add an instance of it to the PercentageCalculatorTests class.

The PercentageCalculatorTests class is a subclass of XCTestCase. It comes packed with the XCTest framework. Each instance of a XCTestCase subclass is in charge of testing a specific part of your project, such as a particular feature.

Instantiate vc in the setup method. This way you will get a “fresh” instance of ViewController for every test method, since setUp() is called before every test method. Update the setUp() method like this:

Now, remember that all test method names must start with the keyword test. Otherwise, Xcode won’t recognise it. Add a new test method testPercentageCalculator() that will verify whether the percentage() method from ViewController works or not.

In Unit Testing you check if a certain chunk of code does its job. The chunks of code being tested are usually just a few lines and typically, you are only testing a single method or function. Unit testing is done by providing the unit of code an input value, allowing that value to run through the code, and then checking to see if the output value is what we expect it to be.

Unit Testing Example

The comparison ‘to what we expect it to be’ part is handled by XCTAssert functions. The simplest XCTAssert function is the XCTAssert(expression: BooleanType). This one takes in a boolean expression (This can be something like 5 > 3, 8.90 == 8.90 or true) and makes the test pass if the expression is evaluated to be true or fail if evaluated to be false.

Try it out! First, add the following line to the testPercentageCalculator() method. Then, move the pointer of your mouse over the diamond icon to the left of the method name in the gutter. As you hover, it transforms into an execute icon that you should click to start the test.

If everything goes well, the test passes and a green checkmark appears next to the method.


Verifying the Percentage Calculation

Now proceed to the real stuff: testing the percentage() method! Call the method with the vc property, which is an instance of ViewController. Give it two floats, 50 and 50 for example, and store the result in a constant p. In this case, p should be equal to 25 (50% of 50 is 25). Check if this is the case with XCTAssert(p == 25) and execute the test method. Replace the testPercentageCalculator() method with the code below:

The test succeeds, which means that the percentage() function of ViewController does its job and we have to look somewhere else for the bug. Perhaps in the updateLabels() method?

Verifying the Labels

Now, add a new test method called testLabelValuesShowedProperly() to verify if the labels display the right text. Again, call a method from ViewController — updateLabels() this time — and check if the the property text of every label corresponds to the text we expect it to display.

Notice that you give the XCTAssert functions a new parameter: a message of type string. This is handy because we have multiple values to check (three XCTAssert calls) for the test to complete. If a test is unsuccessful, this message will tell us what exactly went wrong.

When you try to execute this method, you will get an error complaining that numberLabel, percentageLabel and resultsLabel are nil. How is this possible?

The thing is that I created these labels in my storyboard file and thus they are instantiated once the view is loaded, but since for Unit Tests the loadView() method is never triggered, the labels are not created and thus they are nil. A possible solution for this problem is to call vc.loadView(), but Apple doesn’t recommend doing this in its documentation as it may cause memory leaks when objects that have already been loaded are loaded again.

Instead, you should access the view property of vc, which will in its turn trigger all the required methods, and not simply the loadView() method. Update the code in testLabelValuesShowedProperly().

Notice the use of the underscore ( _ ) to silence the constant name. This is because we don’t actually need the view and will never use it. It basically tells the compiler “Just pretend to access the view and trigger the methods.”

Execute the test. (If you want to execute all the test in our test class, you can also click the square next to “class PercentageCalculatorTests”)


Let’s Fix the Bugs

As you see the test fails! The detailed error messages we entered in this method help us quickly identify the potential cause of the bug. The test is telling us that the resultsLabel are not displaying the right text. So, lets go into the ViewController and see where these label’s text values are being set. After a deeper look into the code of updateLabels() in ViewController.swift we can see what causes the bug:

should be:

Update your code and try to test again. Everything should work now!


In this tutorial, you learned about Unit Testing in Xcode and how it can help you to find bugs in your code. Besides bug prevention, Unit Testing can also be used for Performance Testing and Asynchronous Testing. Another thing that might interest you is UI Testing, where you test how your app performs in real life situations by recording actions on your app. If this sounds interesting, you should definitely check out this WWDC video on UI Testing.

For the final project, you can download it from GitHub.

If you have any questions about Unit Testing or have troubles with the tutorial, be sure to ping me in the comments!

Building a Simple Share Extension in iOS 8 App
Building a Video Search App with YouTube API
Building Action Extensions in iOS 8
  • Eugene Trapeznikov

    Thnx for this tutorial. I got one question.
    Now all methods and outlets in ViewController are public. This ok for testing, as we can access to updateLabels, percentage, resultLabel.text etc. But it is not OK for app architecture. I prefer use private methods and variables as much as possible.
    So, the question is “how to test private methods”?

    • Maxime Defauw

      You can’t and shouldn’t really test private methods in Swift. What you can do instead, is test internal or public methods that use them.

      If you really want to test them, you have two options: 1) Make them public, 2) Add the file to the test project so that they are part of the module and make them internal.

  • Leandro Parice

    Great job!

  • Leon van Bokhorst

    First of… I love AppCoda articles, but this time it made me cringe a little. A critical note:

    While the tutorial teaches some kind of testing, it doesn’t show good testing practices. The latter, however, is essential to get any benefit from unit testing. Concepts of unit testing and UI testing are also mixed in this example. Putting business logic inside a view controller is clearly violating the SOLID principles at the base of unit testing. Calculating logic is not the responsibility of a view controller. Code is heavily coupled spaghetti from the get go this way.

    Why not put the calculator logic inside it’s own classstruct and write unit tests for that class?
    Only use the view controller to tie presentation, business logic and model together (almost no need for testing).
    Then test the workings of the UI inside a UI test target.

    Just my two cents. I have a strong feeling Maxime knows better than this.

  • William Woo

    Excuse me , eventhough I added the sentence ” let _ = vc.view “, the test still failed with the error like this “fatal error: unexpectedly found nil while unwrapping an Optional value”.My system is OS X(10.11.2) and my Xcode version is 7.2 , what on earth is going on here ?

    • Maxime Defauw

      Can you tell me, by looking in the console, what values are nil?

  • Artem


    Author Reply

    let _ = vc.view
    You can use this:

  • Silver


    Author Reply

    Hi. I tried using your tutorial but it doesn’t work.

    “vc = storyboard.instantiateInitialViewController() as! ViewController” causes a “Use of unresolved identifier ‘vc’ error.

    Thus, in func testPercentageCalculator vc isn’t defined and causes the same error

    • vinzo


      Author Reply

      Did you define your variable at the top of the PercentageCalculatorTests class like so ?
      var vc: ViewController!

  • david


    Author Reply

    the repo has an empty project, could you check in the app code and test code… thanks

  • samba


    Author Reply

    Hi, I tried following this article to implement Unit testing, I tried in my sample app, and was getting error
    “Could not cast value of type ‘LoginSam.ViewController’ to ‘LoginSamTests.ViewController’ ” when setUp function was being executed, and it was because of these two lines
    let storyboard = UIStoryboard(name: “Main”, bundle: NSBundle.mainBundle())
    vc = storyboard.instantiateInitialViewController() as! ViewController
    Here NSBundle.mainBundle() was not being properly initiated.

    I googled and found a solution – instead of ‘NSBundle.mainBundle()’ I used ‘NSBundle(forClass: self.dynamicType)’ and from then it was working,
    Please let me know whether I am going correct or missed something while using ‘NSBundle.mainBundle()’
    Thanks in advance

    • Pranav Gupta

      Please use nil in bundle. It is working for me.

  • arash etemad

    Thank you for this tutorial
    These unit tests are white box testing, what is the black box testing for this simple app ?