> For the complete documentation index, see [llms.txt](https://ios-course.cornellappdev.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ios-course.cornellappdev.com/resources/textbook/testing/unit-testing.md).

# Unit Testing

When creating any application, it’s very important that we ensure our apps function properly and maintains that proper functionality for as long as possible. However, this can be quite difficult when working with larger codebases and more complex applications as adding new code may cause undesirable changes to our app. To maintain functionality, we often write unit tests to ensure that our code works properly after making changes to our codebase. In the iOS world, we typically write unit tests for the smallest, yet important, functions that control the logic of our app.

### Getting Started

There are multiple ways to create our testing suite.

1. If creating a brand new project, we can check the box labeled **Include Tests**.
2. For an existing project, go to **File > New > Target > Unit Testing Bundle**. Select the project name and the target to test.

### Testing File

In this chapter, we will be writing unit tests for an app called `Sample`. Notice that a new group gets created ***outside*** of our original project. In our case, it is called `SampleTests`. In this folder, we will create a new Swift file called `SampleTests.swift`.

In a larger, more realistic application, it’s more likely that we will have multiple screens/views. In this case, it’s common to create multiple test files, one for each screen. For example, if our `Sample` app contained a home page, we can have a `HomeSampleTests.swift` file. This keeps our codebase neat and easier to read for other developers.

Let’s analyze the code below:

```swift
import XCTest
@testable import Sample

/// Test suite for Sample.
final class SampleTests: XCTestCase {
    // Test procedures go here.
}
```

1. In order to use Xcode’s testing functionality, we must import the `XCTest` library.
2. We import the name of our main module, which in this case is `Sample`. Note that we must mark it with `@testable`.
3. We create the class representing our test suite. The name of this class should match the name of our file. This class must conform to the `XCTestCase` protocol and is marked with `final` to prevent any unwanted changes to the instances of this class.

### Writing Test Cases

Let’s say we wanted to test a function that counts the number of even numbers in an array. If this function is called `countEvens`, we can call our testing procedure `testCountEvens`.

```swift
func testCountEvens() {
    var result: Int
    
    // Test empty array
    result = countEvens([])
    XCTAssertEqual(result, 0)
    
    // Test array with one even number
    result = countEvens([2])
    XCTAssertEqual(result, 1)
    
    // Test array with more than one even number
    result = countEvens([2,2])
    XCTAssertEqual(result, 2)
    
    // Test array with multiple even and odd numbers
    result = countEvens([1,2,3,4,5,6,6])
    XCTAssertEqual(result, 4)
}
```

However, this code assumes that the `Sample` module that we imported has a publicly accessible function called `countEvens`. If this function was declared as a method inside of a class, we must first instantiate an object of that class and then call the function.

In our example, we are testing for equality so we use the `XCTAssertEqual` function, and pass both values as arguments.

### Running the Test Procedure

There are multiple ways to run the test procedure. The most simple way is to click on the play button next to the name of the function we just created. If we want to run the entire testing suite, we can click on the play button next to the name of our testing class.

Xcode will then build our application and launch the Simulator. If our build succeeds, there will be a popup stating **Build Succeeded**. Note that this DOES NOT mean that our test cases have passed. If our test cases have passed, there will be a **Green** checkmark next to each assertion call. Otherwise, there will be a **Red** cross indicating a failure.

### When to Write Unit Tests

The difficult part in writing unit tests is knowing **when** to write them. It would be OD to test ***every*** single function in our entire codebase, so it’s important that we only test functions that contain complex logic. For example, if we had a function that removes spaces from a String, that may be unnecessary because we can see that when viewing the app. However, if we had a more complex function that contains many edge cases and is difficult or impossible to view through the app, then writing unit tests can help us handle those unseen cases.
