The JUnit XML format is one of the most widely used ways for test automation frameworks and CI tools to save and share test results.
The TestRail CLI can:
- Read a JUnit XML report
- Convert its contents into TestRail entities (Suites, Sections, Cases, Results)
- Import them into TestRail using the API
This guide explains:
- How JUnit XML maps to TestRail
- How
<testsuite>and<testcase>tags are processed - How to use custom properties in JUnit for TestRail
- How to map automation results to custom statuses with
<case_results_statuses>
JUnit report example
<testsuites name="test suites root">
<testsuite failures="0" errors="0" skipped="1" tests="1" time="3049" name="tests.LoginTests">
<properties>
<property name="setting1" value="True"/>
<property name="setting2" value="value2"/>
</properties>
<testcase classname="tests.LoginTests" name="test_case_1" time="159">
<skipped type="pytest.skip" message="Please skip">skipped by user</skipped>
</testcase>
<testcase classname="tests.LoginTests" name="test_case_2" time="650">
</testcase>
<testcase classname="tests.LoginTests" name="test_case_3" time="121">
<failure type="pytest.failure" message="Fail due to...">failed due to...</failure>
</testcase>
</testsuite>
</testsuites>JUnit tags to TestRail Mapping
When parsed by the TestRail CLI, each JUnit report tag is converted to a TestRail entity, as per the table below.
| XML JUnit tags | TestRail entity |
|---|---|
<testsuites> |
Suite |
<testsuite> |
Section |
<testcase> |
Test case |
JUnit <testsuite> handling
Elements with the <testsuite> tag are converted into TestRail sections and their properties are added to the test run description on TestRail. Below you can see an example of a <testsuite> with <property> child tags.
<testsuites name="test suites root">
<testsuite failures="0" errors="0" skipped="1" tests="1" time="3049" name="tests.LoginTests">
<properties>
<property name="setting1" value="True"/>
<property name="setting2" value="value2"/>
</properties>
(...)
</testsuite>
</testsuites>| Attribute or tag | TestRail mapping |
|---|---|
<name> |
Section name |
<property> |
Property names and values are concatenated and added to test run description |
JUnit <testcase> handling
Elements with the <testcase> tag are converted into TestRail test cases and respective test results.
| Attribute | TestRail mapping |
|---|---|
<name> |
Test case name |
<time> |
Test result elapsed time |
- Each
<testcase>is imported as a TestRail test case with a test result - The result’s status is determined by child tags
If there is no tag, the test result will be Passed, while if there is a <failure> tag the test result will be Failed, and if there is a <skipped> tag the result will be Retest. Examples can be seen on the table below.
| XML structure | TestRail status |
|---|---|
|
Passed |
|
Failed |
|
Retest |
The data in the attributes and text of the <failure> and <skipped> tags is added to the test result comment, in a format such as below.
Type: errorType
Message: Failure message
Text: Error (stacktrace)
Adding Custom Test Data via <property>
You can add extra fields, steps, comments, and attachments using special property names. The supported properties and their meaning are listed on the table below.
| Name | TestRail mapping |
|---|---|
testrail_case_field |
Test case field (field_name:field_value) |
testrail_result_field |
Test result field (field_name:field_value) |
testrail_result_comment |
Appends text to result comment |
testrail_result_step |
Adds a step and status (passed, failed, untested) |
testrail_attachment |
Upload attachment in path to test result (max 256MB) |
Below an example of a report with all the listed fields. For more information on how to use these properties, please see the TestRail CLI usage examples page.
<testsuites name="test suites root">
<testsuite failures="0" errors="0" skipped="1" tests="1" time="3049" name="tests.LoginTests">
<testcase classname="tests.LoginTests" name="test_case_1" time="650">
<properties>
<property name="testrail_case_field" value="custom_case_custom_preconds:My preconditions"/>
<property name="testrail_case_field" value="custom_case_type_id:3"/>
<property name="testrail_case_field" value="refs:SAMPLE-1,SAMPLE-2"/>
<property name="testrail_result_field" value="custom_result_version:1.1"/>
<property name="testrail_result_field" value="custom_result_custom_field:custom_value"/>
<property name="testrail_result_step" value="passed: Insert login credentials"/>
<property name="testrail_result_step" value="failed: Click submit"/>
<property name="testrail_result_step" value="untested: User should be logged in"/>
<property name="testrail_result_comment" value="Finding 1"/>
<property name="testrail_result_comment" value="Finding 2"/>
<property name="testrail_attachment" value="path_to/logs.log"/>
<property name="testrail_attachment" value="path_to/screenshot.jpg"/>
</properties>
</testcase>
</testsuite>
</testsuites>Mapping automated tests to existing TestRail case IDs
When using the TestRail CLI to import JUnit XML results, you can explicitly map automated tests to existing TestRail test cases using the test_id property.
This allows you to link your automation tests with the corresponding cases in TestRail instead of creating new cases automatically.
Why use explicit case mapping?
Explicit mapping is helpful when:
- Your team maintains manual and automated coverage for the same test cases
- You want automation results to update existing TestRail cases
- You want consistent reporting across CI/CD pipelines and TestRail runs
The mapping is defined using the <property> tag inside a <testcase> element.
Supported Mapping Formats
The test_id property supports both single and multiple TestRail case IDs.
1. Mapping to a Single TestRail Case
Use a single case ID if the automated test corresponds to exactly one TestRail test case. Example:
<testcase classname="tests.LoginTests" name="test_valid_login" time="120">
<properties>
<property name="test_id" value="C123"/>
</properties>
</testcase>What happens in TestRail
- The automated test result will be uploaded to TestRail case
C123 - The result status (Passed, Failed, Retest) is determined from the JUnit test result structure
2. Mapping one automated test to multiple TestRail cases
A single automated test can validate multiple TestRail cases.
To support this scenario, the test_id property accepts a comma-separated list of case IDs. Example:
<testcase classname="tests.LoginTests" name="test_login_validation" time="200">
<properties>
<property name="test_id" value="C123, C456, C789"/>
</properties>
</testcase>What happens in TestRail
When multiple case IDs are provided:
- The TestRail CLI creates individual test results for each referenced case
- Each case (
C123,C456,C789) receives the same result status - The results appear separately in the TestRail test run
Example outcome in TestRail:
| TestRail Case | Result |
|---|---|
| C123 | Passed |
| C456 | Passed |
| C789 | Passed |
This approach is useful when a single automation test verifies several requirements or behaviors represented by different TestRail cases.
Example JUnit report with case mapping
Below is a simplified example showing both mapping styles.
<testsuites name="automation suite">
<testsuite name="Login Tests">
<!-- Single case mapping -->
<testcase classname="tests.LoginTests" name="test_valid_login" time="120">
<properties>
<property name="test_id" value="C123"/>
</properties>
</testcase>
<!-- Multiple case mapping -->
<testcase classname="tests.LoginTests" name="test_login_validation" time="200">
<properties>
<property name="test_id" value="C123, C456, C789"/>
</properties>
</testcase>
</testsuite>
</testsuites>Best Practices
- Ensure all referenced case IDs already exist in TestRail.
- Use comma-separated IDs without extra characters (e.g.,
C123, C456). - Use this feature when one automation test covers multiple manual test cases.
If the mapping property is not provided, the TestRail CLI will attempt to create or match cases using the Automation ID generated from the JUnit classname and name attributes.
Key Takeaways
- JUnit XML is a universal format for automation results.
- The TestRail CLI imports these into TestRail as Suites, Sections, Cases, and Results.
-
case_results_statusesensures automation statuses align with your TestRail workflow. - Use custom properties to enrich results with extra context, steps, and attachments.
Automated tests can map to one or multiple TestRail cases
Use the
test_idproperty in the JUnit<testcase>elementMultiple case IDs are supported using comma-separated values
Each case receives an individual result in TestRail
Next steps
- Check out the Cypress-saucectl sample project on GitHub for hands-on examples.
- Review the TestRail CLI documentation for additional parameters.
- Contribute improvements or raise questions via your team’s GitHub or TestRail support.
🎓 Level up your testing skills with TestRail Academy!
Explore free, self-paced courses to get the most out of TestRail.