如何将 TestServer 输出记录到测试控制台

问题描述 投票:0回答:3

我目前正在为我的 ASP .Net Core 5 REST 编写集成测试 (https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-5.0) API。 该 API 使用 Serilog 进行日志记录(使用静态 Serilog Logger)。我正在使用 NUnit、Visual Studio 2019、Resharper 运行测试。

我希望 API 代码运行时记录的所有消息都在测试控制台输出中可见。
例如,如果调用此控制器方法:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Serilog;

namespace My.Crazy.Api.Controllers
{    
    public sealed class WheelsController : Controller
    {
        [HttpGet("getwheels")]        
        public async Task<IActionResult> Get()
        {            
            Log.Error("An extremely urgent error");         
            return Ok();
        }
    }
}

我希望测试控制台中显示“极其紧急的错误”消息。
然而,这并没有发生。

这是我的测试服务器设置:

[OneTimeSetUp]
public async Task Setup()
{            
    var hostBuilder = new HostBuilder()
        .ConfigureWebHost(webHost =>
        {
            webHost.UseTestServer();
            webHost.UseStartup<Startup>();  // Startup is the API project's Startup class
    
            Log.Logger = new LoggerConfiguration().WriteTo.Console().CreateLogger();
        });

    var host = await hostBuilder.StartAsync();
    
    _client = host.GetTestClient();
}  

[Test]
public async Task FirstTest() 
{
    var response = await _client.GetAsync("getwheels");
}

我还尝试过使用自定义接收器进行日志记录:

...
// in the test setup
Log.Logger = new LoggerConfiguration().WriteTo.Sink(new CustomSink()).CreateLogger();
...

public class CustomSink : ILogEventSink
{
    public void Emit(LogEvent logEvent)
    {
        var message = logEvent.RenderMessage();
        Console.WriteLine(message);
    }
}

这也不起作用。不过,我已经确认,当 API 代码记录任何消息时,都会调用 Emit 方法。

最后,我尝试使用文件输出:

Log.Logger = new LoggerConfiguration().WriteTo.File("C:\\temp\\test_output.txt").CreateLogger();

按预期工作。不过我还是想登录控制台。

这可能吗?

不幸的是,对 Serilog 或 NUnit 使用其他任何东西都不是一个选择。

c# asp.net-core nunit integration-testing serilog
3个回答
4
投票

我也有同样的问题。经过几天的挖掘,我找到了初始化测试服务器的解决方法。关键在于设置为

true
PreserveExecutionContext
,默认为
false
。将其设置为
true
会将日志输出到测试输出。
False
- 没有服务器日志可见,只有客户端日志可见。

    var path = Assembly.GetAssembly(typeof(MyTestServer))?.Location;

    var directoryName = Path.GetDirectoryName(path);

    if (directoryName == null)
        throw new InvalidOperationException("Cannot obtain startup directory name");

    var hostBuilder = new WebHostBuilder()
        .UseContentRoot(directoryName)
        .ConfigureAppConfiguration(
            configurationBuilder => configurationBuilder.AddJsonFile("appsettings.json", false))
        .UseStartup<Startup>()
        .ConfigureTestServices(services =>
        {
            //adding mock services here
        });

    server = new TestServer(hostBuilder) 
    {
        //set this to true!!!
        PreserveExecutionContext = true 
    };

注意:我们在 .NET7 上运行这些测试(以及被测系统)。我不确定这是否有什么区别。


2
投票

所以我会尝试使用带有记录器的自定义记录器提供程序:

记录器提供者:

public class NUnitLoggerProvider : ILoggerProvider
{
    public ILogger CreateLogger(string categoryName)
    {
        return new NUnitLogger();
    }

    public void Dispose()
    {
    }
}

记录器:

public class NUnitLogger : ILogger, IDisposable
{
    public void Dispose()
    {
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception,
        Func<TState, Exception, string> formatter) {
        var message = formatter(state, exception);
        Debug.WriteLine(message);
    }

    public bool IsEnabled(LogLevel logLevel) => true;

    public IDisposable BeginScope<TState>(TState state) => this;
}    

然后在测试文件中:

var hostBuilder = new HostBuilder()
            .ConfigureWebHost(webHost =>
            {
                webHost.UseTestServer()
                    .UseStartup<TestStartup>()
                    .ConfigureLogging((hostBuilderContext, logging) =>
                     {
                         logging.Services.AddSingleton<ILoggerProvider, NUnitLoggerProvider>();
                     });
            });            

您可以使用其他东西来登录,而不是 Debug.WriteLine(message)。


0
投票

您可以尝试这个库:https://www.nuget.org/packages/Serilog.Sinks.NUnit/

易于使用:

var log = new LoggerConfiguration().WriteTo.NUnitOutput().CreateLogger();

或者

builder.Host.UseSerilog((context, configuration) =>
        {
            configuration.ReadFrom.Configuration(context.Configuration);
            if (builder.Environment.IsDevelopment())
            {
                configuration.WriteTo.NUnitOutput();
            }
        });
© www.soinside.com 2019 - 2024. All rights reserved.