GoogleTest XML Output Format: How It Works and What It Captures for CI Integration

GoogleTest outputs JUnit-compatible XML through the XmlUnitTestResultPrinter class, enabling CI systems to parse test results, failures, timestamps, and custom properties from a standardized report file.

The GoogleTest XML output format provides a machine-readable report of test execution results that integrates seamlessly with Jenkins, GitHub Actions, CircleCI, and other continuous integration platforms. When you invoke the --gtest_output=xml:<path> flag or set the XML_OUTPUT_FILE environment variable, the framework emits a structured document that mirrors the internal UnitTest hierarchy. This format captures everything from execution times and source file locations to detailed failure messages and user-defined properties.

How GoogleTest Generates XML Reports

The XML generation logic resides in the XmlUnitTestResultPrinter class, implemented in googletest/src/gtest.cc. When the test run completes, the method OnTestIterationEnd opens the destination file specified by the user and serializes the entire test hierarchy into XML.

The printer traverses three nested levels:

  1. <testsuites> – Represents the complete UnitTest object (the entire test program).
  2. <testsuite> – Maps to each TestSuite (previously called test case in older terminology).
  3. <testcase> – Represents individual TestInfo objects (specific test functions).

This hierarchy ensures that CI tools can aggregate statistics at the suite level while still accessing granular details for individual test failures.

XML Structure and Reserved Attributes

GoogleTest defines specific attribute sets to maintain JUnit compatibility and provide comprehensive metadata.

The testsuites Root Element

The root <testsuites> element uses attributes defined in kReservedTestSuitesAttributes to summarize the entire test execution:

  • tests – Total test count
  • failures – Number of failed tests
  • disabled – Count of disabled tests
  • errors – Fatal errors
  • time – Total execution duration
  • timestamp – ISO 8601 timestamp of the run
  • random_seed – When test sharding is active

Test Suite Elements

Each <testsuite> element inherits the above attributes and adds kReservedTestSuiteAttributes, specifically the skipped attribute indicating how many tests were skipped in that suite.

Test Case Elements

Individual <testcase> elements carry kReservedTestCaseAttributes:

  • classname – Fully qualified test suite name
  • name – Specific test name
  • status – run or notrun
  • time – Execution duration for this specific test
  • type_param – Type parameter for typed tests
  • value_param – Value parameter for parameterized tests
  • file and line – Source code location

Data Sanitization and XML Safety

Before writing to disk, XmlUnitTestResultPrinter sanitizes all content through three specific methods in gtest.cc:

  1. EscapeXml – Replaces reserved XML characters (<, >, &, ', ") with their corresponding entities (&lt;, &gt;, &amp;, &apos;, &quot;).
  2. RemoveInvalidXmlCharacters – Strips characters that are illegal in XML 1.0 (control characters below 0x20 except tab, newline, and carriage return).
  3. IsNormalizableWhitespace – Normalizes whitespace within attribute values to prevent formatting issues.

These validations ensure that failure messages containing code snippets or binary data cannot corrupt the XML structure, maintaining parseability for CI parsers.

Capturing Test Failures and Custom Properties

Failure Details

When a test fails, OutputXmlTestCaseForTestResult appends a <failure> child element to the <testcase>. This element includes:

  • The failure message and type (e.g., fatal)
  • Optional file and line attributes pointing to the assertion location
  • Full stack traces or failure details wrapped in CDATA sections to preserve formatting and special characters

Custom Properties

Tests can inject metadata using RecordProperty:

TEST(MySuite, MyTest) {
  RecordProperty("category", "integration");
  RecordProperty("ticket", "JIRA-123");
  EXPECT_EQ(1, 1);
}

The printer's OutputXmlTestProperties method validates these names against reserved attributes and writes them as <property name="..." value="..."/> elements inside the <testcase> node. This allows CI dashboards to filter or categorize tests based on custom metadata.

Configuring XML Output for CI Pipelines

GoogleTest supports two primary mechanisms for specifying the output destination:

Command-line flag:

./my_test_binary --gtest_output=xml:report.xml

# Or use xml: alone for default filename test_detail.xml in current directory

Environment variable:

export XML_OUTPUT_FILE=/path/to/report.xml
./my_test_binary

The environment variable is parsed in googletest/src/gtest-port.cc, making it ideal for Bazel-based builds or containerized CI environments where flags might be harder to inject.

Sharding Considerations

When running tests with sharding across multiple workers or machines, each shard writes its own XML file. The timestamp attribute allows CI systems to aggregate results chronologically. Most CI platforms (Jenkins with JUnit plugin, GitHub Actions with test reporters) automatically merge multiple XML files into a unified test report.

Code Examples for CI Integration

GitHub Actions workflow:

steps:
  - name: Run tests with XML output
    run: ./my_test_binary --gtest_output=xml:test_report.xml
  - name: Upload test results
    uses: actions/upload-artifact@v3
    with:
      name: test-results
      path: test_report.xml
  - name: Publish Test Report
    uses: dorny/test-reporter@v1
    if: always()
    with:
      name: GoogleTest Results
      path: test_report.xml
      reporter: jest-junit

Adding searchable metadata:

TEST_F(DatabaseTest, ConnectionTimeout) {
  RecordProperty("component", "database");
  RecordProperty("priority", "high");
  // Test implementation
}

Verification and Testing

GoogleTest's own suite validates XML generation in googletest/test/gtest_xml_output_unittest_.cc, while the Python harness [gtest_xml_test_utils.py](https://github.com/google/googletest/blob/main/googletest/test/gtest_xml_test_utils.py) provides normalization utilities to compare generated XML against golden files. These tests verify:

  • Proper escaping of special characters in failure messages
  • Correct attribute presence for empty vs. populated test suites
  • Behavior when output listeners are disabled or filters are applied
  • File handling for multiple output files and custom naming conventions

Additional file handling tests reside in [googletest/test/gtest_xml_outfiles_test.py](https://github.com/google/googletest/blob/main/googletest/test/gtest_xml_outfiles_test.py), ensuring reliability when CI systems specify output directories or unique filenames.

Summary

  • The XmlUnitTestResultPrinter class in googletest/src/gtest.cc generates JUnit-compatible XML when triggered by --gtest_output=xml or the XML_OUTPUT_FILE environment variable.
  • The format captures hierarchical data through <testsuites>, <testsuite>, and <testcase> elements with reserved attributes defined in kReservedTestSuitesAttributes, kReservedTestSuiteAttributes, and kReservedTestCaseAttributes.
  • Output sanitization occurs via EscapeXml and RemoveInvalidXmlCharacters to ensure well-formed XML regardless of test failure content.
  • <failure> elements contain detailed error messages in CDATA sections, while <properties> elements store custom metadata added via RecordProperty.
  • CI systems can consume these reports directly for test result visualization, trend analysis, and build pass/fail determination.

Frequently Asked Questions

What is the difference between <testsuite> and <testcase> in GoogleTest XML?

A <testsuite> represents a C++ test class or parameterized test fixture, aggregating statistics like total tests and failures for that group. A <testcase> represents a single test method (individual TEST or TEST_F function). The suite contains multiple test cases, and each test case contains its own timing, status, and optional failure details.

How do I prevent GoogleTest XML output from containing invalid characters?

GoogleTest automatically sanitizes output through internal helper methods. The EscapeXml function converts HTML/XML entities, while RemoveInvalidXmlCharacters strips illegal control characters. You do not need manual sanitization; the framework guarantees valid XML even when tests output binary data or crash logs.

Can I generate XML output without using command-line flags?

Yes. Set the XML_OUTPUT_FILE environment variable to your desired path before running the test binary. The framework reads this variable in gtest-port.cc and triggers the XML printer automatically. This approach is particularly useful in Bazel test environments where flags are managed by the build system rather than the user.

Does GoogleTest XML support parallel test execution reports?

Yes. When using test sharding (dividing tests across multiple processes or machines), each shard generates its own XML file with a unique timestamp. CI systems can aggregate these files using the timestamp attribute. The tests and failures counts in each file reflect only that shard's execution, allowing proper consolidation in the CI dashboard.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →