Line and branch coverage
measured on your machine.
renmy runtime collects coverage while it executes your Salesforce Apex tests locally - lines, methods, and both sides of every branch. There is no org, no deploy, and no wait for a Tooling API query.
renmy runtime executes your Salesforce Apex tests on your machine and measures what they touched while it does it.
This is the tool page: what gets measured, which report formats come out, and how to gate on it. For wiring coverage into a pipeline - GitHub Actions, GitLab, SonarQube, Codecov - see CI integration. For the argument about what coverage is actually worth, there is a separate opinion piece.
What gets measured
Coverage is collected by the interpreter as it runs, not reconstructed afterwards. Add --coverage to any renmy test invocation and the run records three things.
Lines. A hit count per executable line. The denominator comes from static analysis of the parsed source, not from whichever lines happened to be executed - so a line nothing reached still counts against you.
Methods. Execution counts per method, rolled up per class, so you can see which methods the suite never entered at all.
Branches. For every if and ternary, renmy runtime tracks the true side and the false side separately. A branch only counts as covered when both sides were taken. Salesforce's own metric does not do this - a test that only ever exercises the happy path shows the branch as fully covered there, and as half covered here.
Reports break down per file, per class, and per method. renmy runtime does not attribute individual lines back to the individual test that covered them.
renmy test "CalculatorTest.*" --coverage
# Code Coverage Summary
#
# Lines: 46 / 3835 ( 1.2%)
# Methods: 14 / 14 (100.0%)
# Branches: 3 / 3 (100.0%)
#
# Coverage by Class:
#
# Calculator.cls 100.0%
# |- add 100.0%
# |- divide 100.0%
# |- factorial 100.0%
# |- isEven 100.0%
# |- multiply 100.0%
# '- subtract 100.0%Report formats
One flag produces five outputs. renmy runtime picks the writer from the file extension you pass to --coverage-report, and --coverage-report implies --coverage, so you never have to pass both.
Summary in the terminal
Line, method, and branch totals plus a per-class and per-method breakdown, printed after the run. There is nothing to open or upload.
renmy test --coverageThe machine-readable report
Per-file hit counts, the executable-line denominator, and per-line branch status (trueExecuted / falseExecuted / covered). This is also the input format for renmy coverage diff.
--coverage-report coverage.jsonBrowsable report
Line, method, and branch percentages up top, then every file with its own bar. Useful as a CI artifact when someone asks where coverage actually went.
--coverage-report coverage.htmlSonarQube, Codecov, quality gates
The standard coverage interchange format, with branch-rate and condition-coverage attributes filled in from the same data the console prints.
--coverage-report coverage.xmlTest results alongside coverage
This is the companion test-results format rather than a coverage format. Pass it in the same run so your CI dashboard gets pass/fail history and coverage from a single invocation.
--results-xml results.xmlThe console summary, the JSON report and the HTML report are Free. The XML formats are Pro.
--coverage-output controls what gets printed inline - console (default) or json. It is independent of --coverage-report, which writes a file.
Coverage and JUnit results can be produced in the same run, so CI does not need a second pass over the suite to get both.
# Console summary (Free)
renmy test --coverage
# JSON report (Free)
renmy test --coverage --coverage-report coverage.json
# HTML report (Free)
renmy test --coverage --coverage-report coverage.html
open coverage.html
# Cobertura XML (Pro)
renmy test --coverage --coverage-report coverage.xml
# Coverage and test results in one run (Pro)
renmy test \
--coverage --coverage-report coverage.xml \
--results-xml results.xmlCoverage diff
A repository-wide percentage tells a reviewer almost nothing. What a reviewer wants is the delta: did this pull request stop covering something that used to be covered?
renmy coverage diff takes two JSON reports - a baseline and the current one - and reports the overall line coverage delta, the per-file regressions and improvements, and the specific line numbers that went from covered to uncovered.
Pass --fail-on-drop and the command exits non-zero when overall coverage decreased. That is the whole flag surface - two positional arguments and one gate.
The diff is computed on line coverage. Branch data is present in the JSON reports themselves, but the delta report is line-based.
# Baseline on main
renmy test "*" --coverage-report base.json
# Then the branch
renmy test "*" --coverage-report pr.json
# Compare, and fail the build on a drop
renmy coverage diff base.json pr.json --fail-on-drop
# Coverage: 78.4% -> 76.9% (-1.5%)
#
# Regressions:
# classes/AccountService.cls 82.0% -> 71.4% (-10.6%) newly uncovered: 44, 45, 46, 91
#
# Improvements:
# classes/LeadRouter.cls 61.0% -> 68.2% (+7.2%)Coverage as a gate
Coverage that nobody enforces is a number on a dashboard. renmy runtime exposes it as an exit code in three places.
Deploy. renmy deploy --min-coverage N runs the local Apex tests against the snapshotted payload and refuses to continue if local line coverage is below the threshold - before Salesforce is contacted at all. See gated deploys.
Release validate. The same --min-coverage gate applies to renmy release validate, and the threshold can be pinned in a named release profile instead of being retyped per invocation. See release management.
Pull requests. renmy coverage diff --fail-on-drop covers the case a fixed threshold misses: a project sitting comfortably at 88% that quietly slides to 84% one merge at a time.
Both --min-coverage gates measure line coverage.
# Refuse the deploy under 80% local line coverage
renmy deploy --target-org staging \
--source-dir force-app \
--min-coverage 80
# Same gate on a validation run
renmy release validate \
--release-profile production \
--min-coverage 80
# PR gate: no regression allowed
renmy coverage diff base.json pr.json --fail-on-dropIn the editor
A coverage report you have to go and open is a report you check once a quarter. Both editor integrations put the same data in the gutter of the file you are already looking at.
Turn on nimbus.coverage.enabled and every run annotates the editor: executed, missed, or a partially taken branch. Method-level percentages appear inline after each signature, so you can see which method is thin without leaving the file.
The plugin adds coverage gutters plus a baseline snapshot: run a coverage pass, set it as the baseline, then toggle the delta overlay to see which lines your change covered - and which it stopped covering.
JetBrains pluginAbout the 75%
Salesforce requires 75% Apex code coverage to deploy to production. Every Salesforce developer knows the number, and most have watched a release window close because a deployment validation discovered the org disagreed with their estimate.
renmy runtime moves that discovery earlier. The same suite that produces your local coverage number runs in seconds on your machine, in your editor, and in CI - so the 75% conversation happens while you are writing the code, not while a validation job is running against production.
The local number is a strong signal but not a substitute for the org's. renmy runtime measures the code it executed locally; Salesforce measures what it executed in the org. Use --min-coverage to catch the obvious failure before you spend a deploy on it.
The more interesting problem is that 75% is a floor, and floors get gamed. A test that calls every method and asserts nothing clears it. So does a test that only ever walks the happy path.
That is what branch coverage is for. It is the cheapest available signal that your suite has actually been down both sides of a decision, and it is the number worth watching once the line percentage stops moving.
We wrote up the longer version of this argument separately.
Apex code coverage is not a test strategyrenmy runtime reports coverage before the org does.
renmy runtime reports line, method, and branch coverage from the test run you were going to do anyway, writes HTML, JSON, and Cobertura, and adds a diff for pull requests and a threshold for deploys.