We have tested some of our classes for the moment. That's great, but we can’t stop there! We have to make sure our entire application is tested!
Well, at least we agreed we'd be testing the Model. Good intentions! ☺️
So, how to be sure that we tested the whole model? We are mere human beings and we can make mistakes. The good news is that there is a tool for that too!
The tool is called code coverage. It analyzes which part of the code is covered by the test. The working principle is simple: it identifies the lines of code that correspond to the tests when running the tests. And the inverted parts of the code by definition are identified as not-covered (or not tested).
Setting up the code coverage
To install the code coverage, we'll have to edit the scheme of our application. To do this, click on the name of the application at the top left:
And select Edit Scheme... in the dropdown:
This will present a configuration dialog:
But what's this scheme? 🤔
A scheme is a set of actions the code can take. We've got 6 that are presented on the left of the pop-up. We've already used 3 of them:
Build: compile the app (cmd + b).
Run: execute the app after compilation (cmd + r).
Test: run the tests (cmd + u).
Back to our task - select Test on the left, check off Gather coveragedata and click Close:
Now, when you run your tests, Xcode will collect the coverage data and indicate the lines of code that were executed during the tests.
Inspecting the Code Coverage
To inspect Code Coverage, you must first run the tests (cmd + u).
Once that's done, switch to the Test navigator:
The test navigator allows you to view all the tests of your application, organized by class. You can also run the tests from this interface by clicking the play button to the right of each test, class, or target.
In the navigator, you can right-click on any test and choose Jump to Report:
You'll be taken to the test report page where you can observe all the tests - if they passed or failed, sort them according to certain criteria. For the moment, what we're interested in is located under the Coverage tab:
On this tab, you can see the coverage percentage of each file and even each function. So you can easily see what your tests are not covering:
As you can see, most of our components are 100% tested through just thoroughly testing the Game class. We did a good job! For more details, you can view the Game.swift file and the coverage information is now available to the right of the file:
On the other hand, if we look at the Tournament.swift file, it shows gaps:
All the red lines on the right will have zero number of executions - they are not tested! We'll fix it shortly!
Setting suitable goals
Of course, ideal test coverage would be 100%. More often than not, optimal is more appropriate than ideal.
What percentage of coverage is optimal? 100%? 90%? 50%?
And the answer is: it's not a question of percentage, but of strategy! 🤓
For example, when working with an MVC model, I recommend aiming to cover the Model 100%. The rest may not be as trivial to test and may not be worth the effort. This makes it come down to answering the question, what percentage of your code is the model?!
The key is to define which parts of the code are the most critical and make sure those parts are fully covered! The overall percentage doesn't matter. It's just a tool.
Closing the gaps!
Game on - let's close the gaps in our model!
It's clear now, we only have one method there remaining to test: the addGame
method!
This method is quite small.
Guess what? It's your turn now! Go ahead and create the tests for the Tournament class!

As you write your tests, some may become redundant. Do not hesitate to delete them!
Here's my version:
import XCTest
@testable import TicTacToe
class TournamentTestCase: XCTestCase {
var tournament: Tournament!
override func setUp() {
super.setUp()
tournament = Tournament()
}
func testGivenGameIsOverWithWinningPlayerOne_WhenAdded_ThenScoreShouldBeOneForPlayerOneAndZeroForPlayerTwo() {
let tournament = Tournament()
tournament.addGame(withWinner: .one)
XCTAssertEqual(tournament.score(forPlayer: .one), 1)
XCTAssertEqual(tournament.score(forPlayer: .two), 0)
}
}
And let's confirm the coverage:
That's it! Nicely done! ☺️
Let's Recap!
You can install the Code Coverage by editing the scheme of your application for the the Test action.
The Code Coverage allows you to identify areas of your code that are not covered by tests.
No need to reach 100% coverage at all costs! It's important to choose a test strategy that is optimal for the project instead. The Code Coverage is a handy tool, but not an ultimate criteria to address.