A few days ago, I wrote about unit testing private methods in Swift. I briefly touched on a topic that is very often overlooked by developers, especially those that are new to unit testing. What are you testing?
Implementation Versus Specification
From a developer’s perspective, unit testing an entity means writing unit tests for every method and property of the entity. In other words, you are writing unit tests to test the implementation of the entity.
What is often overlooked or misunderstood is that unit testing falls in the category of black-box testing. This means that you don’t care how the entity under test does what it does. From the moment you start writing unit tests, you need to stop being a developer and take on the mindset of a tester.
As a tester, you are not interested in how something works. You carefully inspect the public interface of the entity and make sure the entity behaves as specified. You can compare this with someone testing a car. If the tester starts the car, she is not interested in what happens under the hood. The specification says that turning the key should start the car within a predefined time interval. The tester tests the behavior and functionality of the entity under test.
Public Only
By embracing black-box testing, unit testing becomes much easier. You don’t care about the private methods and properties the entity defines. As a tester, you only focus on the public interface of the entity. By unit testing the public interface of the entity, you automatically unit test the private interface. That is the underlying idea.
Code Coverage
There is one caveat. As a tester, you are not interested in the private methods and properties of the entity you are testing. That is fine because that is what black-box testing is about. But it also means that you need to carefully craft the unit tests you write. It can often mean that you need to write multiple unit tests for one public method or property. Why is that?
If you want to have complete code coverage for the entity you are unit testing, you need to make sure every code path of the entity under test is executed, including those of private methods and properties.
Xcode can help you with this. As of Xcode 7, you can ask Xcode to collect code coverage data. Xcode visualizes code coverage for an entity in the gutter on the right of the source editor.
The number indicates how many times the unit tests entered a particular code path. This is helpful to find out where the unit tests you wrote fall short.
It Takes Time
When I first started unit testing Cocoa applications, I tried to reach complete code coverage by unit testing public and private methods. In Objective-C, this is possible with a few tricks. Unit testing private methods and properties is not possible in Swift. And that may be a good thing.
From the moment you start to write unit tests for a project, you need to step out of your role as a developer and take on the mindset of a tester. You need to view the entity you are unit testing as a black box that needs to conform to a specification. It is the specification you need to test. That’s it.