Using ReSharper, how to show debug output during a long-running unit test?
Asked Answered
A

8

42

I'm using xUnit with the ReSharper test runner and the xUnitContrib resharper plugin.

When I have a long-running test, I'd like to be able to output some progress indicator to the Unit Test Output window.

I've tried Debug.WriteLines, Trace.WriteLine and Console.WriteLine. All of which have the same behavior - nothing shows in the output window until the test has completed.

For example:

[Fact]
public void Test()
{
    Debug.WriteLine("A");
    Trace.WriteLine("B");
    Console.WriteLine("C");

    Thread.Sleep(10000);
}

The test shows no output until the 10 seconds have elapsed and the test completes. How do I get output along the way?

UPDATE 1

I tried also with MSTest and NUnit. NUnit is the only one that shows output along the way.

MSTest and XUnit don't return any output until the test completes. The weird part is that while the XUnit and NUnit test output looks like this:

A
B
C

The MSTest output looks like this:

C


Debug Trace:

A
B

Given all of these variations, I think the answer is that it is up to the test runner implementation to decide how and when to output. Does anyone know if it is possible to configure the XUnit test runner?

UPDATE 2

I think this must be a deficiency in xUnitContrib. Posted to their CodePlex issue tracker.

Ahron answered 26/2, 2013 at 15:6 Comment(4)
Debug.WriteLine() works perfectly fine for me when I'm in debug mode. So if you want to log in in a general way I recommend brenton's answerFidelfidela
@derape - No, it doesn't work with xunit. No output appears until the test completes.Ahron
I see, I've not played with XUnit - only NUnit. And NUnit logging does work along the debug threads...Reena
Yes, NUnit does work for this. See my update.Ahron
R
2

XunitLogger uses AsyncLocal<T> to keep track of the logging context so calls to Trace.Writeline and Console.Writeline can be routed to the correct instance of ITestOutputHelper.

Usage:

static class ClassBeingTested
{
    public static void Method()
    {
        Trace.WriteLine("From Trace");
        Console.WriteLine("From Console");
        Console.Error.WriteLine("From Console Error");
    }
}

public class TestBaseSample  :
    XunitLoggingBase
{
    [Fact]
    public void Write_lines()
    {
        WriteLine("From Test");
        ClassBeingTested.Method();

        var logs = XunitLogger.Logs;

        Assert.Contains("From Test", logs);
        Assert.Contains("From Trace", logs);
        Assert.Contains("From Console", logs);
        Assert.Contains("From Console Error", logs);
    }

    public TestBaseSample(ITestOutputHelper output) :
        base(output)
    {
    }
}
Roryros answered 15/4, 2019 at 20:43 Comment(0)
M
36

If you used xUnit.net 1.x, you may have previously been writing output to Console, Debug, or Trace. When xUnit.net 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.x to v2.x should use one of the two new methods instead.

Have a look here for example of how to perform logging with xUnit.net v2:

http://xunit.github.io/docs/capturing-output.html

This is the example:

using Xunit;
using Xunit.Abstractions;

public class MyTestClass
{
    private readonly ITestOutputHelper output;

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

    [Fact]
    public void MyTest()
    {
        var temp = "my class!";
        output.WriteLine("This is output from {0}", temp);
    }
}
Misbegotten answered 8/7, 2015 at 12:15 Comment(1)
This is useful for writing output from within the tests, but when you need to output info in real-time from code called by the tests you have to amend the code being tested to pass in and utilize ITestOutputHelper. I understand the issue of concurrency making it difficult to handle output from the code, I just wanted to point out for others that this solution does have a limitation. It would be nice to leverage something like trace listeners or hijacking the default output stream for the Debug.Write* methods.Pronator
H
14

For NUnit this works:

Console.SetOut(TestContext.Progress);

** The late answer is because I had the same problem, and I just solved it. may help others

Heterogeneous answered 3/2, 2019 at 14:31 Comment(2)
This did not work for me with .net core linux + nunit 3.11Nonsuch
Thanks for updating. Sorry, don’t have an environment to try fix it.Heterogeneous
F
6

ReSharper somehow removed the default listener in unit tests. To display text in the Output window, just add this line:

Debug.Listeners.Add(new DefaultTraceListener());
Flabellum answered 13/11, 2014 at 9:46 Comment(1)
This didn't work for me, in either the Unit Test Sessions window, or the Output window (using MSTest).Hebraist
G
4

I had the same issue for NUnit, now 8 years after you asked the question. :-(

I'm pretty sure that this was implemented by default from Resharper at some point, as I can't remember I had to do this manually before. But sometime down the line, it stopped working.

The solution (for NUnit) is to add this line at the top of your NUnit unit tests.

Console.SetOut(TestContext.Progress)

This makes all your (existing) Console.Out.WriteLine("") output directly to the Resharper Unit Test Runner output section, while the unit test is executing.

Gondola answered 4/2, 2021 at 22:42 Comment(0)
R
2

XunitLogger uses AsyncLocal<T> to keep track of the logging context so calls to Trace.Writeline and Console.Writeline can be routed to the correct instance of ITestOutputHelper.

Usage:

static class ClassBeingTested
{
    public static void Method()
    {
        Trace.WriteLine("From Trace");
        Console.WriteLine("From Console");
        Console.Error.WriteLine("From Console Error");
    }
}

public class TestBaseSample  :
    XunitLoggingBase
{
    [Fact]
    public void Write_lines()
    {
        WriteLine("From Test");
        ClassBeingTested.Method();

        var logs = XunitLogger.Logs;

        Assert.Contains("From Test", logs);
        Assert.Contains("From Trace", logs);
        Assert.Contains("From Console", logs);
        Assert.Contains("From Console Error", logs);
    }

    public TestBaseSample(ITestOutputHelper output) :
        base(output)
    {
    }
}
Roryros answered 15/4, 2019 at 20:43 Comment(0)
R
0

The easiest I've found is to utilize log4net and create a console logger. Along the way, as you're running, you'd call logger.Info("info here"); or log.Debug("info here"); - really whatever your preferred logging level - and the output will show in Resharper Unit Test Sessions.

Read more about the log4net framework on the Apache log4net homepage. The configuration examples will also be invaluable.

Reena answered 26/2, 2013 at 15:19 Comment(1)
Nope. Added log4net, and those messages don't even make it into the unit test output at all. I used a simple console appender - the one from the examples.Ahron
G
0

You may also consider using xunit.NLog which is a very nice and clean way to inject ITestOutputhelper into your SUTs.

http://www.tomdupont.net/2015/06/capture-xunit-test-output-with-nlog-and.html

Gaullism answered 20/6, 2019 at 15:20 Comment(0)
A
0

For Console.WriteLine, this is one way (there may be a better way, but this works for me):

public class ConsoleOutputHelper : TextWriter, ITestOutputHelper
{
    private readonly ITestOutputHelper _helper;

    public ConsoleOutputHelper(ITestOutputHelper helper) => _helper = helper;

    public override void WriteLine(string? message)
    {
        try
        {
            _helper.WriteLine(message);
        }
        catch (InvalidOperationException ex) when (ex.Message.Contains("no currently active test"))
        {
        }
    }

    public override void WriteLine(string format, params object?[] args) => 
        _helper.WriteLine(format, args);

    public override Encoding Encoding => new UTF8Encoding();
}

... then, in your test constructors:

public MyTests(ITestOutputHelper helper) => 
    Console.SetOut(new ConsoleOutputHelper(helper));

... then, in the code you're testing

Console.Out.WriteLine("Beginning something...");

Update

Trace.WriteLine is probably better in production code.

Setup looks like this (need to add and remove the trace listener):

public class MyTests : IDisposable
{
    private readonly TraceOutputHelper _traceOutputHelper;

    public MyTests(ITestOutputHelper helper)
    {
        _traceOutputHelper = new TraceOutputHelper(helper);
        Trace.Listeners.Add(_traceOutputHelper);
    }

    public void Dispose() => Trace.Listeners.Remove(_traceOutputHelper);

... and TraceOutputHelper is very similar to ConsoleOutputHelper above:

public class TraceOutputHelper : TextWriterTraceListener, ITestOutputHelper
{
    private readonly ITestOutputHelper _helper;

    public TraceOutputHelper(ITestOutputHelper helper) => _helper = helper;

    public override void WriteLine(string? message)
        => _helper.WriteLine(message);

    public void WriteLine(string format, params object[] args) => _helper.WriteLine(format, args);
}
Armored answered 18/12, 2021 at 7:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.