On this page
JUnit XML is a de-facto XML format for exchanging automated test results. It began in the Java testing ecosystem, but CI services and test frameworks across many languages now generate or consume it because the format can represent suites, individual cases, durations, failures, errors, skipped tests, and captured output in one portable file.
TestCollab reads JUnit XML through tc report --format junit. For the standard
three-step reporting workflow, start with
Automated Testing in a CI/CD Pipeline with TestCollab.
The standard reporting workflow is: create a Test Plan with tc createTestPlan, run
tests that generate JUnit XML, then upload the file with tc report. Recording a build
and adding a quality gate are optional extensions, not requirements for uploading results.
A JUnit XML Example File
Save this as results.xml. It contains one passed case, one failed case with an
attachment marker, and one skipped case.
<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="3" failures="1" errors="0" skipped="1" time="0.62">
<testsuite name="Authentication" tests="3" failures="1" skipped="1" time="0.62">
<testcase
classname="Authentication.Login"
name="[TC-42] Login succeeds with valid credentials"
time="0.12" />
<testcase
classname="Authentication.Login"
name="[TC-43] Invalid password is rejected"
time="0.43">
<failure message="Expected HTTP 401 but received 200" type="AssertionError">
at authentication.spec.ts:27
</failure>
<system-out><![CDATA[
[[ATTACHMENT|screenshots/invalid-password.png]]
]]></system-out>
</testcase>
<testcase
classname="Authentication.SSO"
name="[TC-44] SSO login redirects to the identity provider"
time="0.07">
<skipped message="Identity provider unavailable in this environment" />
</testcase>
</testsuite>
</testsuites>
The file must be well-formed XML. Attribute order and indentation do not matter, and many
reporters omit aggregate counters or the outer <testsuites> wrapper.
The JUnit XML Elements That Matter
Element or attribute |
Purpose |
|---|---|
|
|
Optional outer container for one or more suites. Some tools write a single
|
|
|
Groups related cases. Suites may be flat or nested. The |
|
|
Represents one test result. Common attributes are |
|
|
Marks an assertion failure. The |
|
|
Usually means the test could not complete because setup, teardown, or the runner failed. Most consumers treat it as a failed case. |
|
|
Marks a case that did not run. It may contain a reason in |
|
|
Captured standard output. TestCollab also reads whole-line attachment markers from it. |
|
|
Duration in seconds in most JUnit dialects. It may appear on cases, suites, and the outer container. |
|
|
Aggregate counters written by many reporters. Consumers may recalculate totals from the
actual |
How a Test Case Status Is Represented
-
Passed: a
<testcase>with no<failure>,<error>, or<skipped>child -
Failed: a case containing
<failure>or<error> -
Skipped: a case containing
<skipped>, or a reporter-specific skipped status attribute
A self-closing <testcase ... /> is normally a passed test, not a missing
result.
Is There an Official JUnit XML Schema?
There is no single, universally authoritative JUnit XML schema that every producer follows. The name describes a family of compatible, de-facto formats produced by JUnit build integrations and adopted by other test tools.
Common differences include whether <testsuites> is present, whether suites are
nested, which aggregate attributes are required, how properties and timestamps are represented,
and whether a runner uses <failure> or <error>. For
interoperability, rely on the common elements above and generate the file with your framework's
maintained reporter instead of constructing XML by hand.
How to Generate JUnit XML
Framework |
Command or output |
|---|---|
|
Playwright |
|
|
pytest |
|
Jest |
Install |
Mocha |
Install |
|
JUnit 4 or 5 with Maven Surefire |
|
|
TestNG |
|
|
PHPUnit |
|
|
Robot Framework |
|
How TestCollab Reads JUnit XML
tc report reads each <testcase> in document order. It uses nested
<testsuite> names for hierarchy when the document contains nested suites; for a
flat report, it uses classname as the suite name when available.
Test Case ID Mapping
For an existing TestCollab plan, place the TestCollab ID in the name or
classname. The recommended form is:
<testcase name="[TC-42] Login should succeed" classname="Authentication" />
Supported explicit patterns are [TC-42], TC-42, id-42, and
testcase-42, matched without case sensitivity. Explicit markers take priority over
every fallback.
A marker-free title is treated as an ID only when the entire title is a slug ending in a hyphen
and digits, such as checkout-42 or login-flow-42. Ordinary prose or
technical names such as Returns HTTP 200, UTF-8, and
SHA-256 are not interpreted as IDs. Use [TC-42] to make the mapping
unambiguous.
Screenshots, Logs, and Traces
Put an attachment marker on its own line inside the case's <system-out>:
<system-out><![CDATA[
test finished
[[ATTACHMENT|test-results/login-failure.png]]
[[ATTACHMENT|test-results/browser.log]]
]]></system-out>
Paths may be absolute, relative to the directory where tc report runs, or relative to
the result file. TestCollab uploads up to 10 files per case, with a maximum of 10 MB per file. A
missing or oversized file produces a warning but does not stop the result upload.
Browser and Operating System Configurations
To route a result to a Test Plan configuration, include its numeric configuration ID in the case
name or classname:
<testcase
name="[TC-42] Login should succeed [config-id-9]"
classname="Authentication"
time="0.4" />
The CLI recognizes config-id-9, config-9, and
[config-id-9]. The value is a TestCollab configuration ID, not the position of a
browser or operating system in your test matrix.
Common JUnit XML Problems
The XML is not well formed
Use UTF-8, close every non-self-closing element, quote attributes, and escape reserved characters.
For example, write & for an ampersand in normal XML text. Prefer your
framework's reporter over hand-written XML.
The result uploads but does not match a case
Add an explicit [TC-42] marker to the test name or
classname. A number elsewhere in ordinary prose is deliberately not treated as a case
ID.
A testcase has no usable name
Give every <testcase> a non-empty name. For existing-plan mode,
the name or classname must also contain the TestCollab ID. Otherwise the CLI reports it as
unresolved and cannot update that case.
Failures appear as passed
Make sure <failure> or <error> is inside the matching
<testcase>. Suite-level failure counters alone do not identify which case
failed.
Your framework creates many XML files
--result-file accepts one file path, not a directory or glob. Configure the reporter
to produce one combined file or merge the reports before calling tc report.
Upload JUnit XML to TestCollab
Install the CLI and expose your API token as TESTCOLLAB_TOKEN. In the standard
workflow, tc createTestPlan creates a plan, your test command generates
results.xml, and tc report uploads that file. If you already have a plan
ID, run:
npm install -g @testcollab/cli
tc report \
--project 45 \
--test-plan-id 123 \
--format junit \
--result-file ./results.xml
For a zero-setup import that creates missing suites, cases, a folder, and a plan from the file:
tc report \
--project 45 \
--format junit \
--result-file ./results.xml \
--auto-create
For an EU-hosted account, add --api-url https://api-eu.testcollab.io. See
Uploading Test Results Using TestCollab CLI
for authentication, plan creation, and reporting options.


