Even though writing unit tests is not my favorite aspect of software development, over the years, I have come to enjoy and appreciate it. Not only is a robust test suite invaluable for any software project, it also makes you a better programmer.
In this article, I would like to show you how you can write better code by writing unit tests. Whenever you write tests for a function or method, you are forced to think about its implementation. You approach the implementation from a different perspective.
Break It Down
Lengthy methods and massive view controllers are almost always symptoms of code smell, subtly telling you that it is time for a round of refactoring. An important benefit of writing tests is that it pushes you to keep methods short and focused.
As a general rule, a method should focus on one thing and one thing only. If you adopt that strategy, methods no longer span dozens or, heaven forbid, hundreds of lines. Lengthy methods are very hard to test. Not only is it difficult to understand what you are testing, too many variables are in play, each affecting the implementation and the corresponding tests.
Keep It Simple
It is better to have a handful of short and focused methods than one monstrous one. Why is that? The most obvious benefit is that concise methods are easier to understand. It is easier to wrap your head around the method's implementation. You have a better understanding of what is going on and what the possible outcomes are.
Another important benefit is the naming of methods. If you create a method that spans dozens of lines and is responsible for half a dozen tasks, then what are you going to name that method? If you break that method down into smaller methods, each with a particular focus or task, naming these methods will be much easier.
By keeping it simple, you gain clarity. By creating massive methods or classes, you create chaos and lose focus.
Dependency Injection
From the moment I became serious about unit testing, I lost my fondness for singletons and fell in love with dependency injection. It felt as if I graduated as a programmer and no longer needed the singleton pattern to glue the pieces of a project together.
Dependency injection is a wonderful concept that is often ignored or discarded in favor of the singleton pattern. Even though I don't dislike singletons, I always ask myself whether there isn't a better solution to solve the problem. And often there is.
Dependency injection, mocking, and testing is a powerful and flexible combination. Mocking and stubbing also become much easier with dependency injection.
Code Coverage
Xcode's support for testing has gradually improved over time. The feature I was most excited about when Apple introduced Xcode 7 in 2015 was the addition of built-in code coverage. Not only does Xcode generate a nice test report, the editor now includes a gutter on the right, showing you if a particular code path was triggered by the project's test suite.
Keep in mind that code coverage isn't magical. It has its flaws and you shouldn't solely rely on code coverage when writing unit tests. That said, it makes it much easier to spot holes in your project's test suite.
My Current Test Setup
Even though XCTest has improved over the years, I almost always use a few additional libraries for making testing easier and more powerful. For Objective-C projects, I have come to love and rely on OCMock, a mocking library for Objective-C. Because OCMock hooks into the Objective-C runtime, there currently isn't an equivalent for Swift projects.
OCMock allows you to test more aspects of your code. It is easy to mock objects and stub methods, which enables you to test parts of your codebase you wouldn't be able to test with only XCTest.
Another library that is great for testing is OHHTTPStubs. As the name implies, this library makes stubbing network requests effortless. With OHHTTPStubs, you no longer have an excuse to ignore networking logic in your project's test suite.
Are You Unit Testing?
Not writing unit tests doesn't make you a bad programmer. But you should ask yourself why you are not writing unit tests. Most studies show that you save time in the long run because breaking changes are easier to find and bugs are less likely to creep into your project's codebase.
Are you writing unit tests? What is stopping you? Questions? Leave them in the comments below or reach out to me on Twitter.