xccov(1) General Commands Manual xccov(1)

xccov - view Xcode coverage data in human-readable or machine-parseable format.

xccov view [--only-targets | --files-for-target target_name | --functions-for-file name_or_path] [--json] report.xccovreport

xccov view --report [--only-targets | --files-for-target target_name | --functions-for-file name_or_path] [--json] result_bundle.xcresult

xccov view [--file-list | --file path] archive.xccovarchive

xccov view --archive [--file-list | --file path] result_bundle.xcresult

xccov diff --json [--path-equivalence <from>,<to>] before.xccovreport after.xccovreport

xccov diff --json [--path-equivalence <from>,<to>] before.xcresult after.xcresult

xccov merge [--outReport path] [--outArchive path] report1.xccovreport archive1.xccovarchive report2.xccovreport archive2.xccovarchive ...

When tests are run with code coverage enabled, Xcode generates two files that contain its representation of coverage data. These are the coverage report, with extension xccovreport, and the coverage archive, with extension xccovarchive. The coverage report contains line coverage percentages for each target, source file, and function/method that has coverage information. The coverage archive contains the raw execution counts for each file in the report.

Using xccov, the contents of these files can be viewed in either human-readable or machine-parseable format. It is also possible to diff two coverage reports to see what changed between them, as well as to merge multiple coverage reports (and their associated archives) together into an aggregate coverage report and archive. Note that when merging reports together, the aggregate report may be inaccurate for source files that changed in between the time that the original coverage reports were generated. If there were no source changes, the aggregate coverage report and archive are guaranteed to be accurate.

The coverage report and archive are stored in the result bundle. If tests are run from Xcode's UI, the result bundle will be written to the Logs/Test subdirectory of your project's DerivedData subfolder, with extension xcresult. For tests run through xcodebuild(1), the -resultBundlePath flag determines where to write out the result bundle. If xccov is passed a result bundle directly, it will extract the report or archive implicitly, as part of the action being requested. Alternatively, the raw report/archive files can be extracted from the result bundle using xcresulttool(1) and subsequently passed to xccov.

Only view the list of targets.
Only view the source files in the target(s) with the given name.
Only view the functions/methods for the file(s) with the given name or path. If supplying a path, note that this is the path to the file when the coverage report was created, and the file need not exist on disk.
View the data in JSON format (default is human readable text).
If specified, map source file paths in before.xccovreport using the provided equivalence. This allows you to diff coverage reports that were produced from the same set of sources, when the sources existed at different file system locations. For example, if before.xccovreport contains code coverage for a file that existed at location /some/location when the report was generated, passing --path-equivalence /some,/tmp will cause the file to be treated as if it existed at /tmp/location. If after.xccovreport then contains code coverage for the same file, but at /tmp/location, then the two files will be diffed together, as expected. Note that if a path prefix contains a comma, then the comma must be escaped with another comma.
When viewing an archive, list all of the files for which the archive contains coverage information.
View the line and subrange execution counts stored in the archive for the file with the given path. Note that this is the path to the file when the archive was created, and the file need not exist on disk.
View the coverage report contained within a result bundle. Either this option or the --archive option must be specified when viewing a result bundle.
View the coverage archive contained within a result bundle. Either this option or the --report option must be specified when viewing a result bundle.
A path where the merged report will be placed. Defaults to 'merged.xccovreport' in the current directory.
A path where the merged archive will be placed. Defaults to 'merged.xccovarchive' in the current directory.

View all the data in a coverage report in human readable format:

xccov view action.xccovreport
Name                                                               Coverage       
------------------------------------------------------------------ ---------------
HelloWorld.app                                                     57.89% (11/19) 
    /tmp/HelloWorld/HelloWorld/AppDelegate.m                       50.00% (3/6)   
        -[AppDelegate applicationWillTerminate:]                   0.00% (0/3)    
        -[AppDelegate applicationDidFinishLaunching:]              100.00% (3/3)  
    /tmp/HelloWorld/HelloWorld/ViewController.m                    50.00% (5/10)  
        -[ViewController setRepresentedObject:]                    0.00% (0/5)    
        -[ViewController viewDidLoad]                              100.00% (5/5)  
    /tmp/HelloWorld/HelloWorld/main.m                              100.00% (3/3)  
        main                                                       100.00% (3/3)  
HelloWorldTests.xctest                                             100.00% (21/21)
    /tmp/HelloWorld/HelloWorldTests/HelloWorldTests.m              100.00% (21/21)
        -[HelloWorldTests testExample]                             100.00% (4/4)  
        -[HelloWorldTests testPerformanceExample]                  100.00% (6/6)  
        -[HelloWorldTests tearDown]                                100.00% (4/4)  
        __41-[HelloWorldTests testPerformanceExample]_block_invoke 100.00% (3/3)  
        -[HelloWorldTests setUp]                                   100.00% (4/4)

View all the data in a coverage report as JSON:

xccov view --json action.xccovreport
{
  "coveredLines": 32,
  "lineCoverage": 0.80000000000000004,
  "targets": [
    {
      "coveredLines": 11,
      "lineCoverage": 0.57894736842105265,
      "files": [
        {
          "coveredLines": 3,
          "lineCoverage": 0.5,
          "path": "\/tmp\/HelloWorld\/HelloWorld\/AppDelegate.m",
          "functions": [
            {
              "coveredLines": 0,
              "lineCoverage": 0,
              "lineNumber": 22,
              "executionCount": 0,
              "name": "-[AppDelegate applicationWillTerminate:]",
              "executableLines": 3
            },
            ...
          ],
          "name": "AppDelegate.m",
          "executableLines": 6
        },
        ...
      ],
      "name": "HelloWorld.app",
      "executableLines": 19,
      "buildProductPath": "\/Users\/Shared\/HelloWorld-ameficnolbeolwbhuqtjojyfcukr\/Build\/Products\/Debug\/HelloWorld.app\/Contents\/MacOS\/HelloWorld"
    },
    ...
  ],
  "executableLines": 40
}

View the list of files that have coverage information in the archive:

xccov view --file-list action.xccovarchive/
/tmp/HelloWorld/HelloWorld/AppDelegate.m
/tmp/HelloWorld/HelloWorld/ViewController.m
/tmp/HelloWorld/HelloWorld/main.m
/tmp/HelloWorld/HelloWorldTests/HelloWorldTests.m

View the line and subrange execution counts for a file in the archive:

xccov view --file /tmp/HelloWorld/HelloWorldTests/HelloWorldTests.m action.xccovarchive/
1: *
2: *
3: *
...
17: 2
18: 2
19: 2
...
31: *
32: 1
33: 1
34: 10 [
(1, 24, 1)
]
35: 10
36: 10 [
(6, 0, 1)
]
37: 1

The notation used here is line number : [line execution count | * if not executable] [[subrange [, subrange]...]]. Subranges have the form (column, length, execution count).

Generate a diff of two coverage reports in JSON:

xccov diff --json before.xccovreport after.xccovreport
{
  "removedTargets": [],
  "lineCoverageDelta": {
    "executableLinesDelta": -1,
    "lineCoverageDelta": 0.075391180654338585,
    "coveredLinesDelta": 2
  },
  "name": "203D12AB-C784-4DA7-8D28-95E8CE20B367",
  "addedTargets": [],
  "targetDeltas": [
    {
      "addedFiles": [],
      "lineCoverageDelta": {
        "executableLinesDelta": 0,
        "lineCoverageDelta": 0.1578947368421052,
        "coveredLinesDelta": 3
      },
      "name": "HelloWorld.app",
      "removedFiles": [],
      "fileDeltas": [
        {
          "removedFunctions": [],
          "functionDeltas": [
            {
              "name": "-[AppDelegate applicationWillTerminate:]",
              "lineCoverageDelta": {
                "executableLinesDelta": 0,
                "lineCoverageDelta": 1,
                "coveredLinesDelta": 3
              }
            }
          ],
          "documentLocation": "\/tmp\/HelloWorld\/HelloWorld\/AppDelegate.m",
          "addedFunctions": [],
          "lineCoverageDelta": {
            "executableLinesDelta": 0,
            "lineCoverageDelta": 0.5,
            "coveredLinesDelta": 3
          }
        }
      ]
    },
    {
      "addedFiles": [],
      "lineCoverageDelta": {
        "executableLinesDelta": -1,
        "lineCoverageDelta": 0,
        "coveredLinesDelta": -1
      },
      "name": "HelloWorldTests.xctest",
      "removedFiles": [],
      "fileDeltas": [
        {
          "removedFunctions": [],
          "functionDeltas": [
            {
              "name": "-[HelloWorldTests testExample]",
              "lineCoverageDelta": {
                "executableLinesDelta": -1,
                "lineCoverageDelta": 0,
                "coveredLinesDelta": -1
              }
            }
          ],
          "documentLocation": "\/tmp\/HelloWorld\/HelloWorldTests\/HelloWorldTests.m",
          "addedFunctions": [],
          "lineCoverageDelta": {
            "executableLinesDelta": -1,
            "lineCoverageDelta": 0,
            "coveredLinesDelta": -1
          }
        }
      ]
    }
  ]
}

2018 Apple Inc.