Capturing Output

In order to assist in debugging failing test (especially when running them on remote machines without access to a debugger), it can often be helpful to add diagnostic output that is separate from passing or failing test results. offers two such methods for adding output, depending on what kind of code you're trying to diagnose.

If you used 1.x, you may have previously been writing output to Console, Debug, or Trace. When v2 shipped with parallelization turned on by default, this output capture mechanism was no longer appropriate; it is impossible to know which of the many tests that could be running in parallel were responsible for writing to those shared resources. Users who are porting code from v1 to v2 should use one of the two new methods instead.

Capturing output in unit tests

Unit tests have access to a special interface which replaces previous usage of Console and similar mechanisms: ITestOutputHelper. In order to take advantage of this, just add a constructor argument for this interface, and stash it so you can use it in the unit test.

using Xunit;
using Xunit.Abstractions;

public class MyTestClass
    private readonly ITestOutputHelper output;

    public MyTestClass(ITestOutputHelper output)
        this.output = output;

    public void MyTest()
        var temp = "my class!";
        output.WriteLine("This is output from {0}", temp);

As you can see in the example above, the WriteLine function on ITestOutputHelper supports formatting arguments, just as you were used to with Console.

In addition to being able to write to the output system during the unit test, you can also write to it during the constructor (and during your implementation of IDisposable.Dispose, if you choose to have one). This test output will be wrapped up into the XML output, and most test runners will surface the output for you as well.

To see output from dotnet test, pass the command line option --logger "console;verbosity=detailed":

Showing live output from ITestOutputHelper

Starting with 2.8.1 (and runners linked against this version), we have added a new configuration option named showLiveOutput to indicate that you would like to be able to see output from ITestOutputHelper live as it occurs, rather than just waiting for the test to finish. This is turned off by default as that was the behavior prior to 2.8.1, and showing live output can add significantly to the noise of the output when not needed. We anticipate that users will turn this option on temporarily while debugging through particular issues rather than be something that's left on all the time.

Capturing output in extensibility classes

Output for unit tests are grouped and displayed with the specific unit test. Output from extensibility classes, on the other hand, is considered diagnostic information. Most runners require you to enable diagnostic output either explicitly with a command line option, or implicitly on an assembly-by-assembly basis by using configuration files.

Each extensibility class has its own individual constructor requirements. In addition, they can take as their last constructor parameter an instance of IMessageSink that is designated solely for sending diagnostic messages. Diagnostic messages implement IDiagnosticMessage from xunit.abstractions. If you're linked against xunit.execution, there is a DiagnosticMessage class in the Xunit.Sdk namespace available for your use.

The extensibility interfaces which currently support this functionality are:

Here is an example of using it in a test case orderer:

using System.Collections.Generic;
using System.Linq;
using Xunit.Abstractions;
using Xunit.Sdk;

public class MyTestCaseOrderer : ITestCaseOrderer
    private readonly IMessageSink diagnosticMessageSink;

    public MyTestCaseOrderer(IMessageSink diagnosticMessageSink)
        this.diagnosticMessageSink = diagnosticMessageSink;

    public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases)
        where TTestCase : ITestCase
        var result = testCases.ToList();  // Run them in discovery order
        var message = new DiagnosticMessage("Ordered {0} test cases", result.Count);
        return result;

Then after enabling diagnostic messages in your configuration file, when run, Visual Studio's output window contains a Tests tab which contains the information from running the tests, including the diagnostic message:

Starting test discovery for requested test run
========== Starting test discovery ==========
[ 00:00:00.00] VSTest Adapter v2.4.5+1caef2f33e (64-bit .NET 7.0.2)
[ 00:00:00.51]   Discovering: OutputExample (method display = ClassAndMethod, method display options = None)
[ 00:00:00.53]   Discovered:  OutputExample (found 1 test case)
========== Test discovery finished: 1 Tests found in 1.4 sec ==========
========== Starting test run ==========
[ 00:00:00.00] VSTest Adapter v2.4.5+1caef2f33e (64-bit .NET 7.0.2)
[ 00:00:00.24]   Starting:    OutputExample (parallel test collections = on, max threads = 24)
[ 00:00:00.26] OutputExample: Ordered 1 test cases
[ 00:00:00.27]   Finished:    OutputExample
========== Test run finished: 1 Tests (1 Passed, 0 Failed, 0 Skipped) run in 282 ms ==========

To see this output, open the Output window in Visual Studio (from the main menu: View > Output), and in the "Show output from" drop down, select "Tests".

Copyright © .NET Foundation. Contributions welcomed at