0% Apex coverage in SonarCloud despite 98% in Sandbox & 99% in JSON report

ALM used

GitLab

CI system used

GitLab CI (2-stage pipeline: Test Run stage → Sonar Scan stage)

Scanner command used

Bash

# Stage 1: Generate coverage
sf apex run test $TEST_ARGS \
  --code-coverage \
  --wait 60 \
  --result-format json \
  --output-dir ./test-results \
  --concise \
  --target-org dev

# Stage 2: SonarCloud Scan
sonar-scanner \
  -Dsonar.organization=***** \
  -Dsonar.projectKey=***** \
  -Dsonar.sources=force-app \
  -Dsonar.apex.coverage.reportPath=./test-results/test-result-codecoverage.json

Languages of the repository

Apex, SFCC

SonarCloud Project URL

Private Project

Error observed

SonarCloud displays 0% code coverage for multiple Apex classes across the project, despite tests running successfully and high coverage being recorded in the generated coverage report.

For example, AGCX_AuthCartPricingHelper.cls shows 98% coverage in the Salesforce Sandbox and 99% coverage inside the generated ./test-results/test-result-codecoverage.json report, but SonarCloud reports 0%.

refer attached snippets

Relevant test-result-codecoverage.json snippet:

JSON

[
  {
    "apexId": "01pXXXXXXXXXXXXXXX",
    "name": "AGCX_AuthCartPricingHelper",
    "type": "ApexClass",
    "numLinesCovered": 180,
    "numLinesUncovered": 2,
    "percentage": "99%"
  }
]

Steps to reproduce

  1. Run Apex unit tests using sf apex run test with --code-coverage and --result-format json.

  2. Save the output to ./test-results/test-result-codecoverage.json.

  3. Pass sonar.apex.coverage.reportPath=./test-results/test-result-codecoverage.json to the SonarCloud scanner step.

  4. Check SonarCloud dashboard — coverage reports 0% across multiple classes.

Hi @Avadhoot_BHARANKAR-S,

Thanks for reaching out. The issue is in the coverage report format. SonarQube’s Apex coverage sensor expects each entry in test-result-codecoverage.json to include a "lines" field. A per-line map of which lines were hit and how many times, like this:

{
  "name": "AGCX_AuthCartPricingHelper",
  "numLinesCovered": 180,
  "numLinesUncovered": 2,
  "percentage": "99%",
  "lines": {
    "1": 1,
    "2": 1,
    "5": 0,
    "12": 3,
    ...
  }
}

The snippet you shared only contains the aggregate totals (numLinesCovered, numLinesUncovered, percentage), there’s no "lines" field. When the sensor can’t find per-line data, it records no hits for any line, resulting in 0% coverage regardless of what the summary numbers say.

The likely cause is the --concise flag in your sf apex run test command. This flag trims output detail and is almost certainly stripping the per-line coverage data from the report. Try removing it:

sf apex run test $TEST_ARGS \
  --code-coverage \
  --wait 60 \
  --result-format json \
  --output-dir ./test-results \
  --target-org dev
  # removed --concise

Then open test-result-codecoverage.json directly and check whether the entries now have a "lines" object. If they do, rerunning the SonarCloud scan should pick up the coverage correctly.

If "lines" is still absent after removing --concise, please share the full content of the coverage JSON file (redacting any sensitive data) so we can verify whether your SF CLI version generates per-line data at all, older versions may not include it.

Hope that helps.

Cheers,

Stevan