Skip to content

Xcode code coverage

EARLY ACCESS

Code coverage for Xcode projects is in early access. Reach out to turn it on for your account. Until then, Tuist doesn't store the coverage your runs upload.

Code coverage tells you which lines of your code your tests executed. Tuist uploads the line coverage of every test run and folds the runs of a commit into one figure, for the project, each target and each file. The dashboard's Code Coverage page shows it per commit and as a trend for each branch.

Tip

If you generate your project with Tuist, follow the generated project guide instead: it measures the code that comes from the binary cache and carries forward the coverage of the test targets selective testing skips.

Setup#

Collect coverage#

Turn the coverage upload on in your Tuist.swift. It's off by default:

swift
import ProjectDescription
let tuist = Tuist(
fullHandle: "my-account/my-project",
testInsights: .testInsights(coverage: .coverage(upload: true)),
project: .xcode()
)

The TUIST_COVERAGE_UPLOAD environment variable (1 or 0) takes precedence over the option, for example to turn the upload off in jobs that run pull requests from forks.

Then turn on Code Coverage in your scheme's test action (Edit Scheme › Test › Options), or pass -enableCodeCoverage YES to the run, and run your tests through tuist xcodebuild test:

bash
tuist xcodebuild test \
-scheme MyScheme \
-enableCodeCoverage YES

Tuist uploads the coverage the run collected along with its test results.

Complete each commit on CI#

A commit's coverage often comes from several jobs: one per scheme, per shard, or per platform. Tuist can't tell when the last of them has reported, so tell it. Once every test job for a commit has finished, run this in a job that depends on all of them:

bash
tuist coverage complete

Until a commit is complete, its coverage shows as In progress and stays out of its branch's trend. The generated project guide describes each status.

Skipped tests#

When a run skips tests with -skip-testing, it measures less than the commit's tests cover, and Tuist can't carry those tests forward from an earlier run. The commit's coverage is Incomplete, unless another run at the commit ran them. To keep a commit complete, run every test in at least one run per commit.

Tests that quarantine skips aren't part of the coverage at all, so they never make a commit Incomplete.

Performance impact#

Collecting coverage adds overhead, mostly after the tests finish, while Xcode writes its coverage report and Tuist exports the coverage. Building and running the tests take about as long as without it.

Querying coverage#

The tuist coverage commands read what the dashboard shows. Without --commit, they read the latest complete commit of --branch, or of your default branch:

bash
tuist coverage show # the project's coverage and its targets
tuist coverage files --commit <sha> # files, least covered first
tuist coverage file Sources/Cart.swift --lines # a file's functions, with per-line counts

All of them accept --json for scripting.