Unit Testing in Xcode6 using XCTest (Swift)

Unit Testing in Xcode6

Unit testing is one of the many most useful tools provided by Apple for developers. It allows us to perform unit tests in the application on specific functions/methods and even to test the performance of any block of code.

Starting Xcode 5, when you create a new application, a target for unit testing is automatically added to the project. If you have noticed this, you might have also observed that a set of files that end with test/tests automatically being added to your project.

We will try to understand what it is in a while. To begin with, we will create a simple project.

1. Create an Xcode Project
We will create a new Xcode project (A single view based template should be fine. Also, I am using Xcode 6.3, which is the latest version available while I am writing this :)) Lets call it “UIDemo” (UI – Unit Testing).
* I am using Swift as the language in this demo *

Now, if you see we have already got an additional target under the project by the name UTDemoTests and some files related to that under the UTDemoTests folder and a file named UTDemoTests.swift. All of this is part of any Xcode project template.

UTDemo1

2. Build and Run the application
The application should Build and Run just fine.

3. Test the application
To see if the unit test target is added properly and what is does, in Xcode, select:

  • Product -> Test

UTDemo2

This will run the test target UTDemoTests. You should see a message saying the test completed successfully. Which means all is well 🙂

4. What just happened?
If you open the UTDemoTests.swift file, you will observe few functions that have been automatically added as part of the template which looks like below.

class UTDemoTests: XCTestCase {
    
    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }
    
    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }
    
    func testExample() {
        // This is an example of a functional test case.
        XCTAssert(true, "Pass")
    }
    
    func testPerformanceExample() {
        // This is an example of a performance test case.
        self.measureBlock() {
            // Put the code you want to measure the time of here.
        }
    }
    
}

Here, you will see that the comments are well put and describes what the function does and what you will use them for. 😉

So quite clear with that right?
Yeah well.. I guess so. But what do I do next?

5. Adding substance to our App
Lets say ours is an app that will compare and tell if two words are Anagrams.

Anagrams:

A word or phrase formed by reordering the letters of another word or phrase, such as satin to stain. 
Lets add a function as below in our view controller to check if two words are anagrams. (or any function that is doing some complex stuff)
    func areStringsAnagrams(string1 :String, string2:String) -> Bool {
        
        if count(string1) != count(string2) {
            // If the lengths of the strings are not same, they cannot be Anagrams.
            return false
        }
        // Create a closure for our sort comparison
        func sortFunc(c1: Character, c2: Character) -> Bool {
            return c1 > c2
        }
        let word1 = sorted(string1, sortFunc) // Sorting String 1
        let word2 = sorted(string2, sortFunc) // Sorting String 2

        for var index = 0; index < count(string1); index++ {
            // Now compare to check if all the letters match
            if Array(word1)[index] != Array(word2)[index] {
                return false
            }
        }
        return true
    }

And it is indeed of utmost importance that this function always yields the correct result. In other words, we need to constantly test the integrity of this function. i.e., to say, we will create a function in the unit testing target to test whether the above function returns the current result.

6. Adding a test case class for testing our custom class.

  • Project -> Add File:
  • iOS – Source – Test Case Class
  • Call it viewControllerTests

UTDemo3

[As per the naming conventions we will suffix “tests” to our corresponding class name which here is viewController]
# Make sure the UTDemoTests target is selected and select the folder to save.

UTDemo4

Now that a new test class is created for viewController, we will add the code for testing.

7. Importing the ViewController class to the XCTestClass: ViewControllerTests
To import a class to a different target (UTDemoTests) the class needs to have public access. In other cases, you might also choose to add the ViewController.swift file to the test target (which you can do by selecting the test target and under Build Phases – Compile Sources click “+” and select and add ViewController.swift).

Other way, which most would suggest as the correct way, is to make the class and the function that you need to test, public. As shown below by adding the public keyword in the class declaration.

public class ViewController: UIViewController {

The compiler might yet throw an error if you are overriding appearance calls. Then you will have to make them public as well.

    override public func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override public func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

Finally make the function that you need to test public.

    public func areStringsAnagrams(string1 :String, string2:String) -> Bool {

Huff. Now what?
Thankfully we are all set now 🙂

8. Testing our function using XCTest
In the created viewControllerTests.swift class under the UTDemoTests, we will import the ViewController class. Which in swift is done by importing the target containing the file and not by importing individual files.

import UTDemo

Before we call any function, we need to create a ViewController instance as below.

    let vc = ViewController()

We will create a function with name testAreStringsAnagrams which tests the output of the function areStringsAnagrams. Note the prefix “test” in the function name as per the naming conventions.

    func testAreStringsAnagrams() {
        // Testing positive case
        let testResult1 = vc.areStringsAnagrams("live", string2: "evil")
        XCTAssertEqual(testResult1, true, "Test 1 Failed")
        // Testing negative case
        let testResult2 = vc.areStringsAnagrams("live", string2: "line")
        XCTAssertEqual(testResult2, false, "Test 2 Failed")
        
    }

XCTAssertEqual is a function that compares two expression for equality and throws an error if otherwise. You can specify any custom message as the last argument to this function. In the above case, we are passing the testResult “testResult1”/“testResult2” returned by our areStringsAnagrams function and the expected result “true”/“false” and if they are equal, the test is successful.

Congratulations! Your test class is all geared up for testing!!

3. Test the application
To execute the test, in Xcode select

  • Product -> Test

UTDemo5

If you see the green check mark against your test function as above, your application is ready to ship! 🙂

Here’s a sample project. (in Swift)

For more details refer to the Apple documentation and make the most of the XCTest framework for a bug free app.

References:

Objective C

Thanks for visiting!

Advertisements

One thought on “Unit Testing in Xcode6 using XCTest (Swift)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s