xUnit.net不捕获控制台输出

时间:2011-08-21 14:42:44

标签: xunit.net

我刚开始测试xUnit.net,但它似乎没有像我期望的那样捕获任何输出(控制台,调试,跟踪)。

这可能吗?我正在使用带有xUnit.net 1.8的示例.NET 4.0类库。

7 个答案:

答案 0 :(得分:38)

xUnit.net 2的情况发生了一些变化。我知道这个问题是关于早期版本的,但是由于人们将在这里进行升级,我认为值得指出这一点。

为了在版本2的测试输出中看到某种输出,您需要在ITestOutputHelper的实例上对测试类(通过构造函数参数)进行依赖,然后使用{{ 1}}此接口上的方法。 E.g:

WriteLine

您可以选择将日志记录框架连接到此接口,方法是注入public class MyTestSpec { private readonly ITestOutputHelper _testOutputHelper; public MyTestSpec(ITestOutputHelper testOutputHelper) { _testOutputHelper = testOutputHelper; } [Fact] public void MyFact() { _testOutputHelper.WriteLine("Hello world"); } } 实现,将所有调用转发到ILog

我承认您默认情况下不会这样做,但出于诊断目的,它可能会非常有用。如果您的测试仅在某些基于云的构建和测试中失败,则尤其如此。测试服务器!

答案 1 :(得分:7)

如果您的Console.Write深入嵌入您不想重构的某个类层次结构中,这可能会有所帮助:

    public MyTestClass(ITestOutputHelper output)
    {
        var converter = new Converter(output);
        Console.SetOut(converter);
    }

    private class Converter : TextWriter
    {
        ITestOutputHelper _output;
        public Converter(ITestOutputHelper output)
        {
            _output = output;
        }
        public override Encoding Encoding
        {
            get { return Encoding.Whatever; }
        }
        public override void WriteLine(string message)
        {
            _output.WriteLine(message);
        }
        public override void WriteLine(string format, params object[] args)
        {
            _output.WriteLine(format, args);
        }
    }

答案 2 :(得分:3)

一般来说,依靠记录测试是一条糟糕的道路。通过/失败应该是测试的结果。而且他们根本不应该进入有足够的东西进行的阶段,因此需要查看跟踪。

xunit.gui.exe显示控制台和跟踪输出,xunit.console.exe没有。如果它很重要,你可以通过制作适当的标准.NET配置条目(Theres'a FileWriterTraceListener来连接一个重定向到文件的TraceListener,如果你谷歌它,你应该可以挂钩)。


更新:正如his blog post中所讨论的那样,Damian Hickey有一个很好的替代示例 - 如https://github.com/damianh/CapturingLogOutputWithXunit2AndParallelTests/blob/master/src/Lib.Tests/Tests.cs

中所示,在xUnit 2 ITestOutputHelper中连接记录

更新2:在某些情况下,可以添加日志记录并将其提供给ITestOutputHelper而不涉及LogContext,方法是使用如下的简单适配器(我只在F#中使用它,抱歉):< / p>

// Requirement: Make SUT depend on Serilog NuGet
// Requirement: Make Tests depend on Serilog.Sinks.Observable

type TestOutputAdapter(testOutput : Xunit.Abstractions.ITestOutputHelper) =
    let formatter = Serilog.Formatting.Display.MessageTemplateTextFormatter(
        "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}", null);
    let write logEvent =
        use writer = new System.IO.StringWriter()
        formatter.Format(logEvent, writer);
        writer |> string |> testOutput.WriteLine
    member __.Subscribe(source: IObservable<Serilog.Events.LogEvent>) =
        source.Subscribe write

let createLogger hookObservers =
    LoggerConfiguration()
        .WriteTo.Observers(Action<_> hookObservers)
        .CreateLogger()
let createTestOutputLogger (output: ITestOutputHelper) =
    let adapter = TestOutputAdapter testOutputHelper
    createLogger (adapter.Subscribe >> ignore)

type Tests(testOutputHelper) =
    let log = createTestOutputLogger testOutputHelper

    [<Fact>] let feedToSut () =
        // TODO pass log to System Under Test either as a ctor arg or a method arg

与使用日志上下文相比,这种方法的不同之处在于,无法获取记录到全局[contextualized] Serilog Logger的信息。

答案 3 :(得分:2)

这里有一个解决方案:https://xunit.codeplex.com/discussions/211566

只需将其添加到您想要调试输出的构造函数或方法中:

Debug.Listeners.Add(new DefaultTraceListener());

答案 4 :(得分:0)

我带着同样的问题降落在这里。这就是我最后得到的。我希望它可以帮助其他人。

How to write a custom target

    /// <summary>
    ///     Use this to output NLog information when running test cases.
    /// </summary>
    [Target("XUnit")]
    public class XUnitTarget : TargetWithLayout
    {
        [RequiredParameter] public ITestOutputHelper OutputHelper { get; set; }

        protected override void Write(LogEventInfo logEvent)
        {
            var logMessage = Layout.Render(logEvent);
            OutputHelper.WriteLine(logMessage);
        }

        /// <summary>
        /// Call this in the test where you wish to enable logging.
        /// </summary>
        /// <param name="testOutputHelper">The xUnit output helper from the test.</param>
        public static void Configure(ITestOutputHelper testOutputHelper)
        {
            var config = new LoggingConfiguration();
            var xUnitTarget = new XUnitTarget
            {
                OutputHelper = testOutputHelper
            };
            config.AddTarget("xUnit", xUnitTarget);
            config.AddRule(LogLevel.Trace, LogLevel.Fatal, xUnitTarget);
            LogManager.Configuration = config;
        }
    }

答案 5 :(得分:0)

这是一个简单的解决方案,我使用 StringBuilder 来捕获输出并仅在测试失败时输出它:

        [Fact]
        public void UnitTest1()
        {
            var sb = new StringBuilder();
            try
            {
                // ... the test code ...
                sb.AppendLine("Put your debug information here.");
                int expected = 1;
                int actual = 2;
                // What I really want to check:
                Assert.Equal(expected, actual);
            }
            // Catch exceptions from the Assert
            catch (Exception e)
            {
                sb.AppendLine("The original failure:");
                sb.AppendLine(e.Message);
                sb.AppendLine(e.StackTrace);
                Assert.True(false, sb.ToString());
            }
        }

因为只有 Xunit Assert.True() 方法接受消息,所以我在 catch 中使用它并通过它的消息提供“日志”信息,如果测试失败,您将看到这些信息。

如果您只在测试中使用 Assert.True() 并提供 sb.ToString() 作为消息,您可以摆脱 try/catch。

答案 6 :(得分:0)

我使用 Console.SetOut 将 Console.Writes 输出到 .NET 测试日志(在 Visual Studio Code 中)。

sftp_readdir

但是通过控制台运行测试更容易

using System;
using System.IO;
using Xunit;
using Xunit.Abstractions;

namespace UnitTest
{
    public class TestClass
    {
        private ITestOutputHelper output;
        public TestClass(ITestOutputHelper output)
        {
            this.output = output;
        }

        public class ConsoleWriter : StringWriter
        {
            private ITestOutputHelper output;
            public ConsoleWriter(ITestOutputHelper output)
            {
                this.output = output;
            }

            public override void WriteLine(string m)
            {
                output.WriteLine(m);
            }
        }

        [Fact]
        public void TestName()
        {
            Console.SetOut(new ConsoleWriter(output));
            Assert.True(ToBeTested.Foo());
        }



        public class ToBeTested
        {
            public static bool Foo()
            {
                Console.WriteLine("Foo uses Console.WriteLine!!!");
                return true;
            }
        }

    }

}

输出将在没有任何测试类修改的情况下显示。

这是不同的,因为 .NET 测试日志窗口使用 TRX 格式(Visual Studio 测试结果文件),请参阅

dotnet test 

有关 TRX 的更多信息。

相关问题