dwyl/learn-apple-watch-development

Unit Testing in Xcode

Opened this issue ยท 4 comments

Testing is Key

So far I've not been able to spend time on researching or implementing tests. There are two types of testing that are possible on iOS.

  • Unit Tests
  • UI Tests

In this issue, my focus will be to figure out How one goes about writing unit tests in XCode

I'm starting by looking at the following Video and blogs on Ray Wenderlich

I'd like to spend ~a day and a half trying to get a reasonable idea about unit testing and I am hoping to write a short walkthrough on how one would unit test for swift 3.1

WIP

What is Unit Testing
Practice that involves testing function/methods of our code that let us verify if the functions work as expected.

func add(x: Int, y: Int) -> Int {
var total = x + y
return total
}

We have created a very simple function which returns the sum of two values. A Unit test would test this function add and see if it returns what we expected.

add(x:1, y:2) should return 3

So how do we go about testing in Swift using XCode?

When creating a new project make sure you've selected the Unit Test checkbox when creating your XCode project.
screen shot 2017-04-03 at 13 00 52

All this will do is create the appropriate folder and a couple of demo files inside the project as seen in the screenshot below
screen shot 2017-04-03 at 13 02 42

We won't be spending any time with the existing file that has been created, so let's get started and create a new file with the Unit Test Case Class Found in iOS Templates
screen shot 2017-04-03 at 13 06 36

You can call this file testingAddition for now, but usually, it's good practice to keep the naming convention similar to the files you will be testing from your real project.

As an example, if you had a view controller called ReturnAddedValuesViewController.swift you'd want to name your test file ReturnAddedValuesViewControllerTest.swift

You'll get the following in your newly created file.

import XCTest

class testingAddFunc: 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.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }
    
    func testPerformanceExample() {
        // This is an example of a performance test case.
        self.measure {
            // Put the code you want to measure the time of here.
        }
    }
    
}

Each Test file contains a:

  • a setUp function which runs before every test.
  • a tearDown function that runs after every test.
  • a testExample function which we can use as a template for all of our unit tests
  • a testPerformanceExample function which we can use for testing performance of our functions

If we delete the example functions testExample and testPerformanceExample and then add a test for our add functions

func testAddFunc() {
        let viewController = ViewController()

       // this assert will fail as the total is 3
        XCTAssertEqual(viewController.add(x: 1, y: 2), 4, "returns 4")
}

Important Note the function name must start with the word test for XCode to recognise it as a test. If the function name was just AddFunc() you would notice the run test button disappear from XCode.
with test
screen shot 2017-04-03 at 18 01 58
without test
screen shot 2017-04-03 at 18 02 09

In the above test, we are first initialising the viewController, and then using the AssestEqual method which checks if the result of the first argument is equal to the result of the second argument.

In our case, passing the add function from the view controller as the first argument and the expected result as the second argument.

We can then run the test by pressing the play button next to the test. **The test should fail as the total should equal to 3 and not 4, if we make the change and then run the test again, we should see the test pass!

func testAddFunc() {
        let viewController = ViewController()

       // this assert will pass as the total is 3
        XCTAssertEqual(viewController.add(x: 1, y: 2), 3, "returns 3")
}

There you have your first unit test in XCode using Swift 3.1.

Issues

Testing by importing the viewController seems to work fine, but I am currently trying to implement something similar for a TableViewController and finding that it is slight more difficult that in the example above. I'll post my solution to that issue here once I've found the best way to tackle it.

So It's taken me a little longer to work this simple readme up as I was trying to implement this simple function inside of the time project.

  • Turns out it is slightly more complicated to pull functions from a tableViewController than just a ViewController. So Once this readme is complete, I'll spend some time trying to figure out the best way to write it for our app.

Update for the Readme above

When testing with a slightly complex app, in our case Time has a table view entry point with a navigation controller. Here are the steps I've taken to get to the functions inside of our TableViewController

    func testExample() {
        
        // we need to initialize the storyboard
        let storyBoard = UIStoryboard(name: "Main", bundle: Bundle.main)
        // then initialize the navigation controller
        let navigationController = storyBoard.instantiateInitialViewController() as! UINavigationController
        // we now need to extract the TableViewController which is the first child of the navigation controller.
        let tableViewController = navigationController.viewControllers[0] as! TasksTableViewController
         
        // Follow the same steps for any tests that may be present inside the viewController. 
        let total =  3
        XCTAssertEqual(tableViewController.addTwoNumbers(x: 1, y: 2), 3)
    }

It's almost as if you're learning something ... ๐Ÿค” ๐Ÿ˜‰ (keep up the great work!) ๐ŸŽ‰