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

> Understand GoogleTest XML output format for CI integration. Learn how it captures test results, failures, and timestamps in a JUnit-compatible report for seamless automation.

- Repository: [Google/googletest](https://github.com/google/googletest)
- Tags: internals
- Published: 2026-08-30

---

**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`](https://github.com/google/googletest/blob/main/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`**:

```cpp
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:**

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

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

```

**Environment variable:**

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

```

The environment variable is parsed in [`googletest/src/gtest-port.cc`](https://github.com/google/googletest/blob/main/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:**

```yaml
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:**

```cpp
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`](https://github.com/google/googletest/blob/main/googletest/test/gtest_xml_output_unittest_.cc), while the Python harness **[[`gtest_xml_test_utils.py`](https://github.com/google/googletest/blob/main/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)](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.