Chapters

Hide chapters

iOS Test-Driven Development by Tutorials

Second Edition · iOS 15 · Swift 5.5 · Xcode 13

15. Adding Features to Existing Classes
Written by Michael Katz

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

You won’t always have the time, or it may simply not be feasible, to break dependencies of a very large class. If you have a deadline to add a new feature and your app is a bowl of spaghetti, you won’t have the time to straighten it all out first. Fortunately, there are TDD techniques to tackle this situation.

In this chapter, you’ll learn strategies to add functionality to an existing class, while at the same time, avoiding modifying it! To do this, you’ll learn strategies like sprouts and dependency injection.

To demonstrate these ideas, you’ll add some basic analytics to the MyBiz app’s main view controllers. After all, every business wants to know what their users are doing.

Getting started

Use the back-end and starter projects from this chapter, as they have a few modifications from the last chapter that you’re going to need. Start up the back end. As always, refer back to Chapter 11, “Legacy Problems” if you need help getting it running.

Your objective is to add a screen to view analytics events for each of the five main view controllers: Announcements, Calendar, Org Chart, Purchase Orders and Settings. This way, the product owners will be able to identify the most-used screens, to figure out where to invest time and resources.

Reporting an analytics event involves:

  • A user-initiated action, like a screen view or button tap.
  • A Report that contains the metadata for the event.
  • Sending that report to the back end.

Sending reports

It will be easiest, in this case, to start from the bottom up: Adding the ability to send reports to the back end. You already have a class that communicates with the back end, API. You’ll create an extension for this class to handle the new functionality while avoiding bloating the current file.

Laying a foundation

First things first, take what you learned in the previous chapter and start with a protocol to keep the dependencies clean and make the work easier to test.

Extending the API

The first step is to send the report. You already have a class that sends stuff to the back end: API. As you may have seen from previous chapters, this class is cumbersome and is interwoven with the rest of the app code. Ideally, you want to add new functionality to it without increasing its complexity or introducing new dependencies.

Sending a report

Now you can start thinking about that report.

Testing the API

In the MyBizTests target, create a new group: Mocks. In that group, create a new file, MockSender.swift, and replace its contents with the following:

Sprouting the send method

API already has a method that takes an object and sends it to the back end: submitPO(po:). It’s too bad that this is specifically for sending purchase orders. You could refactor this method by mapping its dependencies, writing characterization and unit tests, and expanding the API functionality in a reusable way.

Adding analytics to the view controllers

The hard work is over, and the rest should be easy, right? If you think back to the list of steps for analytics, you still need to implement this part:

Not mocking all of the API

You’ve already set up a protocol to help out with the testing: AnalyticsAPI. You don’t need to use API or mock out the RequestSender at all.

Another interesting use case

To implement the prior test, you set up a whole mock instance of AnalyticsAPI. You can use this for testing, without having to worry about the messiness that was previously built into MockAPI as a subclass of API. By using this protocol and starting with a mock implementation, you’ll ensure by default that any new methods you add to the app will be testable.

Passing around dependencies

The analytics feature now works in tests, but not when you run the app. That’s because you still need to pass AnalyticsAPI to the AnnouncementsTableViewController.

Adding more events

So you now have one screen sending reports. It should be straightforward to add reports to additional screens. For example, in OrgTableViewController.swift add the following var:

Challenge

There are few tasks left undone that you should take care of:

Key points

  • You don’t have to bring a whole class under test to add new functionality.
  • You can sprout a method to extend functionality, even if it adds a little redundancy.
  • Use protocols to inject dependencies and extensions to separate new code from legacy code.
  • TDD methods will guide the way for clean and tested features.

Where to go from here?

Although you’ve come a long way, you’ve just scratched the surface of making changes and improving code. You can continue to decompose API into specific protocols like AnalyticsAPI and LoginAPI. You can also now incrementally improve API by replacing delegates with Results and using the RequestSender to make the code more testable.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now