TRX
A .trx file is Visual Studio's test results format: one XML document
per test run, written by dotnet test --logger trx, vstest.console
and Azure DevOps test tasks. It is the .NET counterpart to
JUnit XML — complete and machine-readable, and
unreadable to anyone who opens it in a browser or text editor.
What is inside
<TestRun id="…" name="runner@build-agent 2026-11-08 09:14:02"
xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Times start="2026-11-08T09:14:02.3Z" finish="2026-11-08T09:14:06.9Z" />
<Results>
<UnitTestResult testId="t2" testName="Shop.Tests.CartTests.ApplyCoupon(code: "SAVE10")"
outcome="Failed" duration="00:00:00.3410000">
<Output>
<StdOut>Applying coupon SAVE10 to subtotal 90.00</StdOut>
<ErrorInfo>
<Message>Assert.Equal() Failure: Values differ …</Message>
<StackTrace> at Shop.Tests.CartTests.ApplyCoupon(String code) in CartTests.cs:line 42</StackTrace>
</ErrorInfo>
</Output>
</UnitTestResult>
</Results>
<TestDefinitions>
<UnitTest id="t2" name="ApplyCoupon">
<TestMethod className="Shop.Tests.CartTests" name="ApplyCoupon" codeBase="Shop.Tests.dll" />
</UnitTest>
</TestDefinitions>
<ResultSummary outcome="Failed">
<Counters total="5" executed="4" passed="2" failed="2" notExecuted="1" />
</ResultSummary>
</TestRun>
| Element | Holds |
|---|---|
<Times> |
When the run was created, started and finished |
<Results> |
One <UnitTestResult> per test executed |
<TestDefinitions> |
One <UnitTest> per test, with its class and assembly |
<ErrorInfo> |
<Message> and <StackTrace> of a failure |
<StdOut> / <StdErr> |
What the test printed (ITestOutputHelper, Console) |
<ResultSummary> |
The run's outcome, <Counters>, and run-level <RunInfos> |
<TestLists> / <TestEntries> |
Bookkeeping that links results to definitions |
The result and its class live in different places: a
<UnitTestResult testId="t2"> gets its class from the
<UnitTest id="t2"> under <TestDefinitions>. className can carry an
assembly suffix (Shop.Tests.CartTests, Shop.Tests, Version=1.0.0.0).
The outcome values
outcome |
Read it as |
|---|---|
Passed |
Pass |
Failed |
An assertion failed or the test threw |
Error, Timeout, Aborted |
The test could not finish |
NotExecuted |
Skipped — [Ignore], xUnit Skip, filtered out |
Inconclusive |
Assert.Inconclusive — neither pass nor fail |
PassedButRunAborted, Warning |
Passed, with something wrong around it |
duration is a .NET TimeSpan string — hh:mm:ss.fffffff, with a
d. prefix past a day — not seconds.
The parts that bite
- A run can fail with no failing test. When the test host crashes
(a
StackOverflowException, an out-of-memory kill, a native crash), the adapter is missing, or a data collector errors,ResultSummarysaysFailedand the reason is only in<RunInfos><RunInfo><Text>. Tools that list failing tests show a red build and nothing to fix. - One file per test project.
dotnet teston a solution writes a.trxper project, and withoutLogFileNameeach name includes the user, machine and timestamp — so a glob in the CI step has to collect them all. - Data-driven tests nest. MSTest
[DataRow]results come as a parent<UnitTestResult>with<InnerResults>holding one row each. Count the rows or the parent, never both. testNameis sometimes fully qualified. xUnit writesNamespace.Class.Method(arg: 1), MSTest writesMethod. Strip the class prefix before displaying it next to the class.- No flaky marker. TRX has no retry concept. A rerun
(
dotnet test --retry-failed-testsin newer Microsoft.Testing.Platform, or a pipeline retry) is a second file, so a flaky test only shows up by comparing runs. - The file holds output and paths. Captured
StdOut, machine names, user names and source paths are all in it — check before attaching it to a public issue.
Opening one
Visual Studio (Test Explorer → Open) and Rider read .trx natively;
community converters (trx2html, trxer) turn it into HTML; Azure DevOps reads
it through the Publish Test Results task. For a JUnit file instead, add
the JunitXml.TestLogger package and --logger junit next to the
trx logger.
Or skip all of that: the free
test report viewer reads .trx as-is in
the browser. Test classes become suites, the outcome sets the status,
the failure message and stack trace come from ErrorInfo, StdOut is
kept under the failure, data-driven rows are listed one by one, and a
run that failed with no failing test gets its own entry with the
RunInfo text. Copy the Markdown summary into the pull request, or
publish the report as a link people can comment on.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.
Related
- JUnit XML — the cross-runner format most CI test tabs read
- Test reporter — console, JUnit and HTML outputs per runner, .NET loggers included
- Cobertura — the coverage.xml that coverlet writes next to the .trx
- Share an xUnit report · Share an NUnit report · Glossary