使用Serilog静态记录器将日志输出到Xunit

20

我在我的项目中使用Serilog的静态日志记录器方法——这样可以轻松地在我的类库中调用Log.X,而无需在每个类中注入日志记录器。

然而,当涉及到单元/集成测试时,如果一个测试未通过,从类库中查看错误日志将非常有益(尤其是对于集成测试而言)。

因为我没有将ILogger注入到我的类中(由于使用静态日志记录器),所以我无法创建一个模拟测试日志记录器来将输出写入测试日志。

有人成功地使用Serilog全局(静态)日志记录器将消息输出到XUnit吗?


将 https://github.com/jet/equinox/blob/4d3375389ad2ca24318a302e8ffd562194cf4342/tests/Equinox.EventStore.Integration/Infrastructure.fs#L35-L52 放入 Log.Logger 中(包括一个 WriteTo.Seq() 也非常有用) - Ruben Bartelink
2个回答

31

Serilog.Sinks.XUnit nuget包使得这一过程变得轻松。在项目中引用此nuget,然后你可以在测试中使用静态日志记录器:

using Serilog;
using Xunit;
using Xunit.Abstractions;

namespace XunitToSerilog
{
    public class SampleTest
    {
        public SampleTest(ITestOutputHelper output)
        {
            Log.Logger = new LoggerConfiguration()
            // add the xunit test output sink to the serilog logger
            // https://github.com/trbenning/serilog-sinks-xunit#serilog-sinks-xunit
            .WriteTo.TestOutput(output)
            .CreateLogger();
        }

        [Fact]
        public void Test1()
        {
            Log.Information("goes to test output");
        }
    }
}

2
这里在测试类构造函数中初始化了Serilog+xUnit。那么你必须在每个测试类文件中编写相同的初始化逻辑吗?是否可以在程序入口点全局执行此操作? - Bad
1
@Bad 这里的关键点是将ITestOutputHelper output与记录器连接起来。ITestOutputHelper由XUnit注入到类构造函数中。这个设计决策很有意义,这样测试运行器就可以将输出分配给特定的测试。您可以从一个基类派生出所有的测试类,这样做初始化的代码就会更少。或者你可以使用共享测试上下文(参见CollectionFixture)找到另一种方法。 - rachri
我认为真正不错的是在依赖注入阶段连接输出,就像在启动ConfigureServices方法中那样。你可以做类似loggerFactory.AddProvider这样的事,并指定XunitTestOutputLoggerProvider,但我想实际上指定一个Serilog提供程序。我不知道该如何做到这一点。 - Mark Lauter

0

另一方面,如果您想测试日志的输出,一个快速而简单的方法可能是:

using FluentAssertions;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace TestNamespace;

public class TestClass
{
    private readonly TestOutputHelper _logOutput;

    public TestClass(ITestOutputHelper logOutput)
    {
        _logOutput = (TestOutputHelper)logOutput;

        Log.Logger = new LoggerConfiguration()
            .WriteTo.TestOutput(_logOutput)
            .CreateLogger();
    }

    [Fact]
    public async Task TestMethodShould()
    {
        var foo = "bar";
    
        // method under test should use serilog to Log.Warn(...);
        var result = await classUnderTest.MethodUnderTest(foo);
        
        _logOutput.Output.Should().NotBeNullOrEmpty();
        _logOutput.Output.Trim().Split("\n").Should().HaveCount(1);
        _logOutput.Output.Should().Contain("WRN] log message that should return");
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接