An Introduction to Swift Unit Testing

July 17th, 2014

Filed under: Cocoa, Xcode | 4 comments

This article shows you how to get started unit testing Swift code in Xcode with XCTest. If you’ve written Objective-C unit tests using XCTest or OCUnit, you should be able to smoothly transition to Swift after reading the article. But Objective-C unit testing experience isn’t required to read this article.

Because Xcode 6 is currently in beta, I can’t show any screenshots due to Apple’s non-disclosure agreement. When Xcode 6 is officially released, I may update this article with screenshots.

Create a Unit Test Target

Your XCode project needs a unit test target in order to run unit tests. The easiest way to create a Swift unit test target is to create a new project. If you create a Cocoa application project or an iOS application project that uses Swift, Xcode includes a unit test target for the project.

If you’re converting an existing Objective-C project to Swift, you must manually add a Swift unit test target.

  1. Choose File > New > Target.
  2. Select Other under iOS or OS X on the left side of the New Target Assistant.
  3. Select Cocoa Testing Bundle from the list of targets.
  4. Click the Next button.
  5. Enter the name of the target in the Product Name text field.
  6. Choose Swift from the Language menu.
  7. Click the Finish button.

Add a Unit Test Class

When it creates a unit test target, Xcode includes a unit test class. You can get through this article with the class Xcode supplies, but eventually you’ll need to add a unit test class to your project.

  1. Choose File > New > File.
  2. Select Source under iOS or OS X on the left side of the New File Assistant.
  3. Select Test Case Class from the list of files.
  4. Click the Next button.
  5. Enter the name of your class in the Class text field.
  6. Choose Swift from the Language menu.
  7. Click the Next button.
  8. Choose a location to save the file.
  9. Make sure the class is a member of the unit test target, not the application target.
  10. Click the Create button.

Anatomy of a Unit Test Class

When you create a unit test class, it initially looks similar to the following code:

import Cocoa
import XCTest
class MyTests: 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.
		}
	}
}

The code starts by importing the Swift modules that are needed to run the tests. XCTest is the framework for unit testing Swift code. I created a Mac application so my example imports the Cocoa framework. If you have an iOS project your unit test class will import the Cocoa Touch framework.

Next comes the class declaration. I named my class MyTests, which inherits from XCTestCase. Swift unit test classes inherit from XCTestCase.

Finally come the test methods.There are four methods initially.

  • The setUp method gets called before each test runs. If you have initialization code you call before running each test, place the code in the setUp method so you don’t have to repeat the code in each test.
  • The tearDown method gets called after each test runs. If you run any cleanup code after running each test, place that code in the tearDown method so you don’t have to repeat the code in each test.
  • The testExample method provides an example of a test method. You can remove this method if you want.
  • The testPerformanceExample method provides an example of a performance test case, which measures how long a task takes to complete. You can remove this method if you want.

Test Methods

After creating your unit test class, you can move on to writing test methods. A Swift test method has the following conditions:

  • It must begin with the word test.
  • It takes no arguments.
  • It returns no value.

The following code shows an example of declaring a test method:

func testDoSomething() {

}

Assertions

Each test method needs an assertion, which determines whether or not the test passes. XCTest assertions start with XCTAssert. If you start typing XCTAssert, Xcode’s code completion should show you a list of all the available assertions, but the following are the most widely-used assertions:

  • XCTAssertNotNil asserts a variable is not nil.
  • XCTAssertTrue asserts a condition is true.
  • XCTAssertFalse asserts a condition is false.
  • XCTAssertEqual asserts two values are equal.
  • XCTAssertEqualObjects asserts two objects are equal.
  • XCTAssertEqualWithAccuracy asserts two floating-point values are equal.

XCTest assertions take two or more arguments. The first arguments depend on the assertion. XCTAssertTrue and XCTAssertFalse take a condition as the first argument. The XCTAssertEqual assertions take two arguments at the start: the two items you’re checking are equal. After the assertion testing arguments comes the error message, which is a string. Xcode displays the error message if the assertion fails. If you want to show the value of a variable in the error message, place the variable name in parentheses in the error message, prefixed by a backslash character.

\(variableName)

The following code shows an example of an assertion involving a variable named length:

XCTAssertTrue(length == 12, “The length should have been 12. Actual length: \(length)")

Running Your Tests

Xcode provides multiple ways to run your tests.

  • Choose Product > Test.
  • Run them from the editor. There is a small button in the gutter next to the unit test class and each test method. Click the button to run the tests.
  • Run them from the test navigator. Choose View > Navigators > Show Test Navigator to show the test navigator.

Running the tests from the editor or the test navigator gives you more control over what tests are run. But the Xcode 6 betas run every Swift test, even if you tell Xcode to run only one test. Hopefully this will be fixed by the time Xcode 6 is released.

A Test Method Example

If you’ve written unit tests in Xcode before, you know enough now to unit test your Swift code. For those of you new to unit testing, I’m providing a sample test method that tests the result of multiplying two negative numbers.

func testMultiplyingTwoNegativeNumbersYieldsAPositiveValue() {
	let x = -6
	let y = -4
	let product = x * y 

	XCTAssertTrue(product > 0, "Multiplying two negative numbers should yield a positive number. Product: \(product)")
}

The test is simple. Give two variables negative values and multiply them. Assert the product is greater than 0.

If you paste the code into your unit test class and run the test, it should pass. If you want to check the error message, change the condition of the assertion from the product being greater than zero to being less than zero.

More Information

You can learn more about unit testing in Xcode and Swift by watching the Testing in Xcode 6 session from Apple’s WWDC 2014 Session Videos. Apple also has multiple sessions on Swift programming that you should also watch to learn more about Swift.

Facebooktwittergoogle_plusredditmail

Tags: ,


4 thoughts on “An Introduction to Swift Unit Testing

  1. Francisco Rivas says:

    Hello, I am wondering if it is possible to write the unit tests in Swift and using them in an application already written Objective-C. Thank you very much in advance

  2. Mark Szymczyk says:

    Francisco,

    I have not tried writing unit tests in Swift for an Objective-C application, but it should be possible. You need to create an Objective-C bridging header to expose your Objective-C files to the Swift unit test classes. Apple has a document, “Using Swift with Cocoa and Objective-C”, that provides more detailed information on mixing Swift and Objective-C code. You can read the document in Xcode or at Apple’s developer site.

  3. DWY says:

    Helo, just starting out and have a PlayGround created, test cases written with assertions but al of the run/test/debug options are grayed out. Any ideas? Thanks.

  4. Mark Szymczyk says:

    DWY,

    Do you have a project? I haven’t tried unit testing a standalone playground. You may need a project to be able to run and test.

    If you have a project, go into the scheme editor and make sure your application is selected in the Executable menu. Whenever I’ve been unable to run a project, it’s because None was chosen in the Executable menu.

Leave a Reply

Your email address will not be published. Required fields are marked *