Intro to Test Driven Swift

Introduction

Welcome to the last lesson of Learn Swift with Bob. There are three objectives. First, you will learn why Swift seems slow when you work with playgrounds. Second, you will learn how Swift and Apple engineers send those red marks on the left side and tell you what to do. Last, you will learn how compile Swift files using Terminal only. I assume you already know how to navigate between folders using Terminal.

Problem

Learn how to create safe apps

Swift Optimization

Type Speed Usage
-Onone slow debug
-O fast release
-Ounchecked Super fast testing

Assert Function

The standard Swift library come with five assertion functions:

  • assert()
  • assertionFailure()
  • precondition()
  • preconditionFailure()
  • fatalError()

Assert

You may enter a closure block to assert. It returns either true or false.

  1. assert(true) // pass

Let us create a function that may return assert(false).

  1. func enterName(name: String) {
  2. if name == "" {
  3. assert(false, "You must enter a full name")
  4. } else if name == "Bob" {
  5. assert(false, "There is only one Bob")
  6. }
  7. }
  8. enterName(name: "Bob")
  9. // Error

Here is another example.

  1. var expectedResult = 10
  2. var actualResult = 10
  3. assert(actualResult == expectedResult, "The actual result doesn't match with the expected")

You may use #file and #line

  1. print("File: \(#file)")
  2. print("Line: \(#line)")

AssertionFailure

It destroys no matter what.

  1. import Foundation
  2. let randomNumber: Int = Int(arc4random_uniform(3))
  3. switch randomNumber {
  4. case 0, 1, 2:
  5. print(randomNumber)
  6. default:
  7. assertionFailure("Unexpected index \(randomNumber)")
  8. }

If randomNumber contains any number besides 0, 1, 2, it will crash the program.

Precondition

It is identical to Assert. However, it is also called when Swift is compiled at -0.

  1. let expectedNumber = (1, 3)
  2. let actualNumber = (1, 3)
  3. precondition(actualNumber == expectedNumber, "\(actualNumber) is not the same as \(expectedNumber)")

Note: I don’t recommend using Precondtion or PreconditionFailture since the user has no idea what the error is.

PreconditionFailure

Identical as AssertionFailure. It is called during -O.

FatalError

It is useful for terminating an app no matter what.

  1. let number: Int = Int(arc4random_uniform(100))
  2. func enterNumberReturnString(index: Int) -> String {
  3. switch index {
  4. case 0, 1, 2:
  5. return "\(number)"
  6. default:
  7. // assertionFailure("Unexpected index \(number)")
  8. // abort()
  9. fatalError("Unexpected index \(number)")
  10. }
  11. }

@noreturn, the compiler confirms that the marked function will not return. The application would terminate instead.

Debug (Onone) Release (O) Test (Ounchecked)
assert() YES NO NO
assertionFailure() YES NO NO
precondition() YES YES NO
preconditionFailure() YES YES YES
fatalError() YES YES YES

Note: YES - is for termination.

Source Code

8006_intro_test_driven.playground

Reference

Swift Assertions - Andy Bargh

Swift asserts - the missing manual by Marcin Krzyżanowski

Optimizing Swift Performance

Apple: Optimization Tips

Conclusion

You’ve completed the objectives. You’ve learned the three ways to compile Swift files. You’ve learned how to make your program crash so that you are able to guarantee that the entire app should work if it passes. However, as the title indicates, this is an intro to test driven development. You may join my mailing list to sign up for the upcoming courses. See you in the final video of Learn Swift with Bob.

Note: Learn Swift with Bob is available on Udemy. If you wish to receive a discount link, you may sign up here.