【发布时间】:2011-10-31 14:56:16
【问题描述】:
我刚开始测试 xUnit.net,但它似乎没有像我预期的那样捕获任何输出(控制台、调试、跟踪)。
这可能吗?我正在使用带有 xUnit.net 1.8 的示例 .NET 4.0 类库。
【问题讨论】:
标签: xunit.net
我刚开始测试 xUnit.net,但它似乎没有像我预期的那样捕获任何输出(控制台、调试、跟踪)。
这可能吗?我正在使用带有 xUnit.net 1.8 的示例 .NET 4.0 类库。
【问题讨论】:
标签: xunit.net
如果您的 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);
}
public override void Write(char value)
{
throw new NotSupportedException("This text writer only supports WriteLine(string) and WriteLine(string, params object[]).");
}
}
【讨论】:
Write?
我使用 Console.SetOut 将 Console.Writes 输出到 .NET 测试日志(在 Visual Studio Code 中)。
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;
}
}
}
}
但是通过控制台运行测试更容易
dotnet test
那里将显示输出,而无需对测试类进行任何修改。
这是不同的,因为 .NET 测试日志窗口使用 TRX 格式(Visual Studio 测试结果文件),请参阅
dotnet test -h | grep logger
有关 TRX 的更多信息。
【讨论】:
这是我使用 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。
【讨论】:
我带着同样的问题来到这里。这就是我最终的结果。我希望它可以帮助别人。
/// <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;
}
}
【讨论】:
xUnit.net 2 的情况发生了一些变化。我知道问题是关于早期版本的,但由于人们会在执行升级后登陆这里,我认为值得指出这一点。
为了在版本 2 的测试输出中看到某种输出,您需要在测试类中(通过构造函数参数)对Xunit.Abstractions.ITestOutputHelper 的实例进行依赖,然后使用WriteLine 方法在这个界面上。例如:
public class MyTestSpec
{
private readonly ITestOutputHelper _testOutputHelper;
public MyTestSpec(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}
[Fact]
public void MyFact()
{
_testOutputHelper.WriteLine("Hello world");
}
}
您可以选择将您的日志框架连接到此接口,或许可以通过注入将所有调用转发到ITestOutpuHelper 的ILog 实现。
我承认默认情况下您不想这样做,但有时出于诊断目的,它可能非常有用。当您的测试仅在某些基于云的构建和测试服务器上失败时尤其如此!
【讨论】:
MyDatabaseFixture)被传入这个MyTestSpec构造函数而不是ITestOutputHelper?
dotnet test 时没有看到输出。在运行 .NET Core 测试运行程序时使用此接口有什么秘密吗? (编辑:看起来日志仅在断言失败后显示,因此意图似乎是日志只能用于调试故障,我可以忍受,不情愿。)
dotnet test --logger "console;verbosity=detailed"
总的来说,依赖日志记录和测试是一条糟糕的道路。通过/失败应该是测试的结果。而且他们根本不应该达到这样的阶段,即发生了足够多的事情以至于需要查看跟踪。
xunit.gui.exe 显示控制台和跟踪输出,xunit.console.exe 不显示。如果它很重要,您可以连接一个 TraceListener,它通过制作适当的标准 .NET 配置条目来重定向到一个文件(有一个 FileWriterTraceListener,如果您用谷歌搜索它,您应该能够连接它)。
更新:正如his blog post 中所讨论的,Damian Hickey 有一个很好的可能替代示例 - 将日志记录连接到 xUnit 2 ITestOutputHelper,如 https://github.com/damianh/CapturingLogOutputWithXunit2AndParallelTests/blob/master/src/Lib.Tests/Tests.cs 中所示
更新 2:在某些情况下,可以添加日志记录并将其提供给 ITestOutputHelper,而不涉及 LogContext,方法是使用如下简单的适配器(我只有在 F# 中,抱歉):
// 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
这种方法与使用日志上下文的不同之处在于,不会获取到全局 [上下文化] Serilog Logger 的日志记录。
【讨论】:
这里有一个解决方案:https://xunit.codeplex.com/discussions/211566
只需将其添加到您想要调试输出的构造函数或方法中:
Debug.Listeners.Add(new DefaultTraceListener());
【讨论】: