Skip to content

t1k:unity:testing:code-coverage

FieldValue
Moduletesting
Version3.1.7
Efforthigh
Tools

Keywords: code coverage, quality, testing, unity

/t1k:unity:testing:code-coverage

Package: com.unity.testtools.codecoverage v1.3.0. Measures which lines execute during tests; generates HTML/XML reports. For DOTS library coverage, GUI mode only — batch mode does NOT capture Packages/ assemblies.

Critical Limitation — UPM Packages + Batch Mode

Section titled “Critical Limitation — UPM Packages + Batch Mode”

Batch mode reports 0% coverage for all Packages/com.the1studio.* assemblies. This is a Unity engine limitation — not a config issue. No flag (assemblyFilters, pathFilters, --burst-disable-compilation) fixes it.

See references/batch-mode-limitation.md for all attempted workarounds.

How “Enable Code Coverage” Is Stored (Investigation 2026-03-14)

Section titled “How “Enable Code Coverage” Is Stored (Investigation 2026-03-14)”

The toggle uses two separate mechanisms:

  1. CoveragePreferences (persisted)CoveragePreferences.instance.SetBool("EnableCodeCoverage", value) writes to ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json via UnityEditor.SettingsManagement.Settings API
  2. Coverage.enabled (runtime) — Unity C# API flag, set alongside the preference. This is the actual runtime gate that controls instrumentation

Settings.json starts EMPTY (m_DictionaryValues: []) even after enabling coverage via the GUI toggle. The file only populates when the user toggles the checkbox inside the Code Coverage window (Window > Analysis > Code Coverage). Enabling it elsewhere (e.g., batch mode -enableCodeCoverage flag) does NOT write to Settings.json.

On domain reload, the Code Coverage window reads Coverage.enabled (runtime API) to sync its state — it does NOT read from Settings.json for the initial enable state.

Edit ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json directly:

{
"m_Dictionary": {
"m_DictionaryValues": [
{ "type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "EnableCodeCoverage",
"value": "{\"m_Value\":true}" },
{ "type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "IncludeAssemblies",
"value": "{\"m_Value\":\"DOTSRPG.Core,DOTSRPG.Combat\"}" }
]
}
}

Important: Writing this file persists the preference, but Coverage.enabled is only set at editor startup or when the Code Coverage window reads this file. After editing, call refresh_unity MCP tool or restart Unity.

GUI Workflow (Required for Library Coverage)

Section titled “GUI Workflow (Required for Library Coverage)”
  1. Window > Analysis > Code Coverage (ensure “Enable Code Coverage” checked)
  2. Window > General > Test Runner > EditMode tab
  3. Click “Run All”
  4. Report auto-opens: CodeCoverage/Report/index.html

Use for demo code in Assets/Demos/ — NOT for Packages/:

Terminal window
/path/to/Unity -batchmode -nographics -projectPath "/path/to/project" \
-runTests -testPlatform EditMode -testResults ./TestResults.xml \
-debugCodeOptimization --burst-disable-compilation \
-enableCodeCoverage \
-coverageResultsPath ./CodeCoverage/Results \
-coverageOptions "generateHtmlReport;assemblyFilters:+<assets>;pathFilters:-**/Tests/**"

Required flags:

  • -debugCodeOptimization — Debug mode required; Release mode gives inaccurate data
  • --burst-disable-compilation — Burst prevents coverage instrumentation
  • -enableCodeCoverage — Activates Coverage.enabled at startup
PatternCaptures
+<assets>All Assets/ assemblies (batch-safe)
+<packages>Package assemblies (batch mode = 0%, GUI = full)
+my.package.nameSpecific package by name
-**/Tests/**Exclude test files from coverage
  • Burst blocks ALL runtime system coverage[BurstCompile] systems show 0% even in GUI mode because Burst-compiled code bypasses managed C# instrumentation. Must disable Burst (Jobs > Burst > Enable Compilation uncheck) before running tests for coverage. Batch mode uses --burst-disable-compilation but that flag only works for Assets/ code
  • GUI mode + Burst enabled = misleading results — Tests PASS (362/362) but runtime systems show 0% coverage. Only non-Burst code shows coverage: struct constructors (DamageEvent, StatusEffect), constants classes, pure utility structs called directly (SpatialHashGrid at 92.8%)
  • ISystem IS coverableOnCreate/OnUpdate instrumented when Burst is disabled
  • Components are data-only — No logic = no coverage needed
  • IJobEntity coverage — Job body covered when Burst disabled and system is covered
  • [ExcludeFromCoverage] — Use sparingly; doesn’t reliably exclude lambdas
  • Settings.json empty — Normal. Only populates after explicit GUI toggle in Code Coverage window
  1. Jobs > Burst > Uncheck Enable Compilation
  2. Window > Analysis > Code Coverage > Enable Code Coverage
  3. Window > General > Test Runner > EditMode > Run All
  4. Review report at CodeCoverage/Report/index.html
  5. Re-enable Burst after coverage run (performance impact otherwise)

Batch mode is useless for package coverage. Instead:

  • Run tests in batch (no coverage flags), use test count as coverage proxy
  • 362 tests passing = strong coverage signal for com.the1studio.dots-core
  • For true coverage metrics, run GUI mode locally with Burst disabled before merging

CodeCoverage/Report/index.html — auto-generated after test run with coverage enabled.

  • dots-unit-testing — Test fixture patterns (DOTSTestBase, ISystem isolation)
  • dots-tester agent — Test execution with MCP tools
FileContent
references/batch-mode-limitation.mdAll attempted workarounds + evidence