Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can output be captured from within IClassFixture<T>? #214

Open
jdvor opened this issue May 6, 2020 · 8 comments
Open

Can output be captured from within IClassFixture<T>? #214

jdvor opened this issue May 6, 2020 · 8 comments

Comments

@jdvor
Copy link

jdvor commented May 6, 2020

As outlined here https://xunit.net/docs/capturing-output.html the message sink is indeed injected into fixture constructor (the type is Xunit.Sdk.TestFrameworkProxy.MessageSinkWrapper), but none of the messages sent to it are visible anywhere.
The documentation does not state that IClassFixture extensibility is supported or should work, on the other hand some conforming type is injected into the constructor.

Is there any way how to capture output from class fixtures?

xunit: 2.4.1
netcoreapp2.2
VS: Microsoft Visual Studio Enterprise 2019 Version 16.5.1

@bradwilson
Copy link
Member

It might not be clear enough, but the message sink that's sent into fixture constructors can only accept diagnostic messages (that is, messages which implement IDiagnosticMessage).

The "output" concept is only available while a test is running. The validity starts when the test class is created (and the test-specific ITestOutputHelper implementation is injected), and ends after the test class has been disposed. Output is associated with a single test execution; there is no higher level/larger scope version of output.

@jdvor
Copy link
Author

jdvor commented May 6, 2020

So Xunit.Sdk.TestFrameworkProxy.MessageSinkWrapper injected into fixture instances is supposed to publish nothing? (In other words, the fact that it is injected in the first place is some kind of bug).
Because the sink instance is not null, it is indeed possible without exception to pass diagnostic messages to it, but the only difference from the documentation (the example under "Capturing output in extensibility classes") is there are no messages written to Visual Studio's Tests output window.

IDiagnosticMessage is of course the only type the sink accepts in its OnMessage method, so I don't see any room for confusion there. Yet you felt it is needed to specifically mention it, which might signal some complexity I am not aware of and which is not visible from the interface.

Maybe I should re-phrase the question in two parts:

  1. Why is Xunit.Sdk.TestFrameworkProxy.MessageSinkWrapper injected into class fixtures? Is it supposed to do something / be usable from within the fixture?
  2. Is there any way how to get diagnostic information to VS output window from within a fixture?

@jdvor
Copy link
Author

jdvor commented May 6, 2020

As for 2. Debug.WriteLine seems to work, but of course the output is not in Tests tab, but Debug tab of VS' Output window.
Such solution is probably only (somewhat) useful when running tests in VS, but it is probably of no use during execution by CI server.

@jdvor
Copy link
Author

jdvor commented May 6, 2020

as simplified example as possible:

namespace XunitOutput1
{
    using System;
    using System.Diagnostics;
    using Xunit;
    using Xunit.Abstractions;
    using Xunit.Sdk;

    public class UnitTest1 : IClassFixture<SomeSutFixture>
    {
        private readonly SomeSutFixture fixture;

        public UnitTest1(SomeSutFixture fixture, ITestOutputHelper output)
        {
            // This is a nonsense of course; there is a little chance to meaningfully marry a shared resource producing messages from fixture
            // with per-test ITestOutputHelper instances.
            ////fixture.Sut.Some += (_, e) => output.WriteLine($"message {e.N}");

            this.fixture = fixture;
        }

        [Fact]
        public void Test1()
        {
            fixture.Sut.Foo(1);
        }

        [Fact]
        public void Test2()
        {
            fixture.Sut.Foo(2);
        }

        [Fact]
        public void Test3()
        {
            fixture.Sut.Foo(3);
        }
    }

    public class SomeSutFixture
    {
        public SomeSut Sut { get; }

        public SomeSutFixture(IMessageSink sink)
        {
            Sut = new SomeSut();

            // Does not work; can't find messages anywhere.
            Sut.Some += (_, e) => sink.OnMessage(new DiagnosticMessage($"Message {e.N} by sink.OnMessage"));

            // Works; message are visible in Output/Debug window.
            Sut.Some += (_, e) => Debug.WriteLine($"Message {e.N} by Debug.WriteLine");
        }
    }

    public class SomeSut
    {
        public event EventHandler<SomeEventArgs> Some;

        public void Foo(int n)
        {
            if (n != 1)
            {
                Some?.Invoke(this, new SomeEventArgs(n));
            }
        }
    }

    public class SomeEventArgs : EventArgs
    {
        public int N { get; }

        public SomeEventArgs(int n)
        {
            N = n;
        }
    }
}

@bradwilson
Copy link
Member

no messages written to Visual Studio's Tests output window

Diagnostic messages don't show up as "output", they show up in the test runner console messages. And they are disabled by default, so you must enable them: https://xunit.net/docs/configuration-files#diagnosticMessages

Debug.WriteLine seems to work, but of course the output is not in Tests tab, but Debug tab of VS' Output window.

That's because we do not intercept Debug.WriteLine. So seeing the output in the Debug tab in VS is exactly what it's supposed to do.

@jdvor
Copy link
Author

jdvor commented May 9, 2020

Diagnostic messages don't show up as "output", they show up in the test runner console messages. And they are disabled by default, so you must enable them: https://xunit.net/docs/configuration-files#diagnosticMessages

I know (I've read the documentation which I've linked in original post) and I've enabled them in app.config.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="xunit.diagnosticMessages" value="true"/>
  </appSettings>
</configuration>

Yet they do not show up in any VS output windows. According the documentation they should be visible in VS Output pane, tab Tests, like so:

------ Run test started ------
[xUnit.net 00:00:00.1131667] Discovery starting: OutputExample (name display = ClassAndMethod)
[xUnit.net 00:00:00.1600619] Discovery finished: OutputExample (1 tests)
[xUnit.net 00:00:00.1739819] Execution starting: OutputExample (method display = ClassAndMethod, parallel test collections = True, max threads = 8)
OutputExample: Ordered 1 test cases
[xUnit.net 00:00:00.1739819] Execution finished: OutputExample
========== Run test finished: 1 run (0:00:00.4369286) ==========

@bradwilson
Copy link
Member

Since this appears to be an issue with either VSTest or the xUnit.net VSTest adapter, I'm moving the issue to the latter's repository for further investigation.

@bradwilson bradwilson transferred this issue from xunit/xunit May 10, 2020
@rvvincelli
Copy link

rvvincelli commented Dec 15, 2020

Hi, thanks for this clarification; using the sink works for me (xunit 2.4.1, VSTest Adapter 2.4.3, VS19 16.8.2), diag messages show up in the console after turning on the setting in the xunit conf. Tx,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants