Swift 2.0 and Unit Testing

Preface

As we mature, as programmers and professionals, we see things differently. Our approaches and perspectives change and our paradigms shift. We start weighing things on a different scale, silently laughing at our follies we made in adolescence. I admit, initial days of my journey as a programmer, I used to program like an artist. I would make a basic structure first, then perfect it slowly towards the requirement by debugging and thus narrowing the gap between the current and target state. It had been working fine, but the biggest problem with that approach was — debugging almost always takes up more effort and time than actual development. Though I love debugging, but also, in many cases, I was having to change a lot of code to make things optimized, which could be avoided by a preplanning the coding approach which is evidently lacking in the current modus operandi.

Then I got introduced to Test Driven Development (TDD) approach. I wouldn’t say that I was in love with the approach at the first instance and started following that everywhere — no. Apart from the fact that like most daytime programmers I do not have the luxury to follow any new approach as soon as I encounter, I actually was skeptic about the approach and never thought it to be practical. However, I decided to give it a fair chance and tried it out on a couple of home grown projects, and I liked it. Lot less debugging, hugely less worry about changing code and its impact, and lot less effort to develop.

Today’s post is not about TDD, but actually about Unit Testing. In the past days, writing a unit test for the piece of code written by the developer seemed impractical and frown upon by the developers and major part of unit testing was done manually by the developer before handing over to the QA team. However, as I mentioned before, the programming community is now matured enough not to ignore the boons of unit testing. Apple’s flagship IDE Xcode comes with XCTest unit testing framework bundled within. We will dive into the framework and testing techniques in this post.

What is Unit Testing

In the term Unit Testing, unit represents the smallest possible testable bit of code written. It might be a method, a class or a whole functionality, based on the viewpoint of the programmer. A test is a piece of code that exercises the code written to make an app, a library or a functionality and provides a status of pass or fail based on some given criteria. The pass and fail of a test is derived by checking for correct state of certain objects that are expected to change their states after an operation is done, or whether a piece of code throws an exception based on a specific set of data that passes through it where it is supposed to throw the exception. There are performance tests too, which measures the execution time of a set of code block and determines the pass or fail status based on preset benchmarks.

Different types of Unit Testing

As the unit testing frameworks matured, more and more types of unit testings were made possible. Along with the functional testing framework, non-functional unit tests such as Performance Testing were made possible in the unit testing frameworks. In Xcode 6, Apple introduced performance testing capabilities in it’s XCTest framework. In Xcode 7 they introduced UI Testing. We will dive into each type of testing one by one and see how this can be done.

Setting up Unit Test Project

I will use Xcode 7.0 beta (7A121l) for demonstrating the Unit Testing. When a project is created using Xcode it also sets up a Unit Testing project with it if “Include Unit Tests” checkbox is checked.

Screenshot_8_10_15__11_36_PM

Once the project is created, you will find a Test folder is created alongside with it too. Now we will see how we write tests. TDD approach talks about writing the test cases before you even start writing code. This approach asks you to write test cases for the code that does not exist and run the test case which fails. Then write the code to make it pass. However, here, for the sake of simplicity and for the sake of the very basic nature of the post, I will show a basic test scenario based on the code already written.

Main Project

So, I will start with a very basic project I created just for the demonstration purpose of this article called BookCatalog. The project is actually a slight variation of the time stamp sample project you get when you create a master detail project for the first time. So you have a plus button at the top and tapping that the table gets populated with name of books from an array which contains names of books and their authors.

Simulator_-_iPhone_6_-_iPhone_6___iOS_9_0__13A4305g_

So to demonstrate how tests work, I take an example of a method called "populateBookModel". The method looks something like below:


let books = ["The Great Gatsby by F. Scott Fitzgerald",
             "The Prince by Niccolo Machiavelli",
             "Slaughterhouse-Five by Kurt Vonnegut",
             "1984 by George Orwell",
             "The Republic by Plato",
             "Brothers Karamazov by Fyodor Dostoevsky",
             "The Catcher in the Rye by J.D. Salinger",
             "The Wealth of Nations by Adam Smith",
             "For Whom the Bell Tolls by Ernest Hemingway",
             "The Grapes of Wrath by John Steinbeck",
             "Brave New World by Aldous Huxley",
             "How To Win Friends And Influence People by Dale Carnegie",
             "The Rise of Theodore Roosevelt by Edmund Morris",
             "Dharma Bums by Jack Kerouac",
             "Catch-22 by Joseph Heller",
             "Walden by Henry David Thoreau",
             "Lord of the Flies by William Golding",
             "The Master and Margarita by by Mikhail Bulgakov",
             "Bluebeard by Kurt Vonnegut",
             "Atlas Shrugged by Ayn Rand",
             "The Metamorphosis by Franz Kafka",
             "Another Roadside Attraction by Tom Robbins",
             "White Noise by Don Delillo",
             "Ulysses by James Joyce",
             "The Young Man’s Guide by William Alcott",
             "Blood Meridian, or the Evening Redness in the West by Cormac McCarthy",
             "Seek: Reports from the Edges of America & Beyond by Denis Johnson",
             "Crime And Punishment by Fyodor Dostoevsky",
             "Steppenwolf by Herman Hesse",
             "East of Eden by John Steinbeck",
             "Essential Manners for Men by Peter Post",]

var bookObjects = [AnyObject]()

func populateBookModel () {
    books.map { 
       (book: String) -> String in bookObjects.append(Books(bookName: book.componentsSeparatedByString(" by ")[0], author: book.componentsSeparatedByString(" by ")[1]))
       return book
    }
}

The above code actually parses the above array, populates the Books model.

class Books {
    
    let bookName: String
    let author: String
    
    init(bookName: String, author: String) {
        self.bookName = bookName
        self.author = author
    }
    
}

Test Project

So, I would like to test this populateBookModel method to check whether the books are getting populated nicely. So, I would create a file in the test project with a name which signifies the class I am going to test. This file will contain all the tests for all the methods/functionalities I like to test from the MasterViewController class. Now I have to decide how to verify that the method actually executed without any problem? If you examine the code of the MasterViewController as displayed above, you will find that I actually take the books from books array and populate them into bookObjects array. So, if I check the count of these two arrays and they match, that would indicate that the population was successful. To achieve this, I write the following test —

import XCTest
@testable import BookCatalog

class BookCatalogTests: XCTestCase {
  func testpopulateBookModel() {
          let masterVC = MasterViewController()
          masterVC.populateBookModel()
          XCTAssert(masterVC.bookObjects.count == masterVC.books.count, "Book objects are \(masterVC.bookObjects.count) and books are \(masterVC.books.count) in number")
    }
}

If you execute the above test, the test will pass as the count of the books array matches with the count of bookObjects. So, the above test says that the population was successful.

Sample Project

I have put together a project which shows how to setup your unit testing project and write unit tests. All the examples in this article can be found there. You can grab the project at this location.

Conclusion

Unit Testing is a vast subject. With this article, I have touched the tip of the iceberg — because I wanted to write down my learnings as fast as possible. As I go on exploring more I will post more articles on unit testing. I hope the post was helpful and interesting to you and you will love writing unit tests as much as I do now. Please feel free to post comments and suggestions as always!

Advertisements

2 thoughts on “Swift 2.0 and Unit Testing

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