Reader small image

You're reading from  Test-Driven iOS Development with Swift - Fourth Edition

Product typeBook
Published inApr 2022
PublisherPackt
ISBN-139781803232485
Edition4th Edition
Right arrow
Author (1)
Dr. Dominik Hauser
Dr. Dominik Hauser
author image
Dr. Dominik Hauser

Dr. Dominik Hauser is an iOS developer working for a small company in western Germany. In over 11 years as an iOS developer, he has worked on many different apps, both large and small. In his spare time, Dominik builds small (often silly) apps and explores how he can become a better iOS developer. He talks at conferences, writes books, and is active in the iOS community in general. His most successful open source component (in terms of stars) is a pull-to-refresh control for a table view that consists of an actual SpriteKit game. Before Dominik became an iOS developer, he was a physicist, researching the most powerful photon sources within our galaxy.
Read more about Dr. Dominik Hauser

Right arrow

Chapter 7: Building a Table View Controller for the To-Do Items

If you have talked to other iOS developers about unit testing and the test-driven development of iOS apps, you might have heard the opinion that the user interface of iOS apps is not testable and also shouldn't be tested. Many developers state that it is enough to check whether the user interface is correct by running the app during development and testing it manually.

That might be true for the initial implementation of the user interface. During the development process, you run the app often on the iOS simulator or on your test devices and most bugs and errors in the user interface are quite obvious.

However, the main benefit of a user interface that is backed by unit tests is the ability to fearlessly refactor code that is no longer perfect. As a developer, you gain experience every day, and each year, Apple releases new APIs that make our code easier to understand and sometimes easier to write. Long-living...

Technical requirements

Adding the table view for the to-do items

As always, we start with a test. But before we can write the test, we need a new test class. Follow these steps to add a test class for the view controller that shows the to-do items:

  1. Select the ToDoTests group in the Project navigator and add a new file from the File menu in Xcode. Select the template from iOS | Source | Unit Test Case Class and then click Next. Insert the name ToDoItemsListViewControllerTests.
  2. In the created file, add @testable import ToDo and remove the two template test methods.
  3. Add a property for the system under test (sut):
    // ToDoItemsListViewControllerTests.swift
    class ToDoItemsListViewControllerTests: XCTestCase {
     
      var sut: ToDoItemsListViewController!
     
      override func setUpWithError() throws {
        // Put setup code here. This ...
      }
     
      override func tearDownWithError() throws {
        // Put teardown code here. This ...

Testing the data source of a table view

In this section, we will implement parts of the data source for the table view using test-driven development. We will use the traditional approach by using the view controller as the data source. In the next section, we will switch to a diffable data source. Our challenge in this section is to write the tests so that they are independent of the actual implementation of the data source.

But first, we need to talk about test doubles.

Adding a test double

In the film industry, doubles are used in scenes that are too dangerous for the actor. The double must look and act like the actor. In software testing, we have something similar: test doubles. Test doubles look and act like a piece of code, but can be controlled completely from within the test. For example, to test the data source of our table view, we need to connect the view controller with a store of to-do items. We could use the store we already implemented. But this would make the...

Refactoring to a diffable data source

In iOS 13, Apple introduced the UITableViewDiffableDataSource class. This class manages the update of a table view when the data changes and it can be used as the data source of any table view. It should be used, when possible, because implementing updates of a table view is a bit complicated and can lead to strange bugs and even crashes. In addition, the code needed to set up such a data source is often easier to read and reason about than the traditional implementation we used in the previous section.

Follow these steps to transform our implementation to one that uses a diffable data source:

  1. A diffable data source manages the data in the table view using a section and an item that both need to conform to the Hashable protocol. We already have an item we can use in the diffable data source, the ToDoItem structure. However, this structure does not yet conform to Hashable. To make it conform to that protocol, add the following code to...

Presenting two sections

As we have already refactored to a diffable data source, supporting two sections in the table view is quite easy. Follow these steps to implement two sections:

  1. As always, we need to start with a failing test. Add the following test to ToDoItemsListViewControllerTests:
    // ToDoItemsListViewControllerTests.swift
    func test_numberOfSections_shouldReturnTwo() {
      var doneItem = ToDoItem(title: "dummy 2")
      doneItem.done = true
      toDoItemStoreMock.itemPublisher
        .send([ToDoItem(title: "dummy 1"),
               doneItem])
      let result = sut.tableView.numberOfSections
      XCTAssertEqual(result, 2)
    }

In this test, we set a to-do item and a done item to the table view using toDoItemStoreMock. The name of the test method should also include what the preconditions of the tests are. We use a shorter name in the book because...

Implementing the delegate of a table view

When the user selects a to-do item in the list of items, the details of the to-do item should be shown in a dedicated view. We will implement the actual navigation between the different views of the app in Chapter 11, Easy Navigation with Coordinators. In this section, we will implement the required code in ToDoItemsListViewController.

Follow these steps to prepare ToDoItemsListViewController for navigation to the detail view:

  1. Let's assume we already have a delegate that will provide a method the view controller can call. Add the following test method to ToDoItemsListViewControllerTests:
    // ToDoItemsListViewControllerTests.swift
    func test_didSelectCellAt_shouldCallDelegate() throws {
      let delegateMock = 
        ToDoItemsListViewControllerProtocolMock()
    }

Xcode tells us that it cannot find the ToDoItemsListViewControllerProtocolMock type. This type is meant to be a mock object for the real delegate...

Summary

In this chapter, we have learned how to test table views and table view cells. We experienced the value of useful unit tests when refactoring a large part of the code. By switching from the traditional table view data source to the diffable data source, we improved the code and the behavior of the app while still keeping the existing tested functionality.

In the next chapter, we will use the knowledge we gained to create a detailed view and its view controller.

Exercises

  1. Implement the setting of the location label using test-driven development.
  2. Try to figure out in the documentation of Xcode how to add section headers when using a diffable data source. We will implement the section headers in Chapter 11, Easy Navigation with Coordinators.
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Test-Driven iOS Development with Swift - Fourth Edition
Published in: Apr 2022Publisher: PacktISBN-13: 9781803232485
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Dr. Dominik Hauser

Dr. Dominik Hauser is an iOS developer working for a small company in western Germany. In over 11 years as an iOS developer, he has worked on many different apps, both large and small. In his spare time, Dominik builds small (often silly) apps and explores how he can become a better iOS developer. He talks at conferences, writes books, and is active in the iOS community in general. His most successful open source component (in terms of stars) is a pull-to-refresh control for a table view that consists of an actual SpriteKit game. Before Dominik became an iOS developer, he was a physicist, researching the most powerful photon sources within our galaxy.
Read more about Dr. Dominik Hauser