I'm currently writing an integration test (https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-5.0) for my ASP .Net Core 5 REST API. The API is using Serilog for logging (with the static Serilog Logger). I am running tests with NUnit, Visual Studio 2019, Resharper.
I want all the messages, that are logged during the runtime of the API code, to be visible in the test console output.
For example, if this controller method is called:
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();
}
}
}
I expect the "An extremely urgent error" message to be shown in the test console.
However, this is not happening.
Here is my TestServer setup:
[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");
}
I have also tried logging with a custom Sink:
...
// 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);
}
}
This does not work as well. However, I have confirmed that the Emit method is being invoked when API code logs any message.
Finally, I have tried using a File output:
Log.Logger = new LoggerConfiguration().WriteTo.File("C:\\temp\\test_output.txt").CreateLogger();
which worked as expected. However, I still want to log in the console.
Is this possible?
Using anything else for Serilog or NUnit is unfortunately not an option.
WebApplicationFactory provides multiple ways to customise your application in integration tests, but at it's core, it provides a way to run your application's Host instance in memory.
So I would try with a custom logger provider with logger:
LoggerProvider:
public class NUnitLoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName)
{
return new NUnitLogger();
}
public void Dispose()
{
}
}
Logger:
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;
}
Then in the test file:
var hostBuilder = new HostBuilder()
.ConfigureWebHost(webHost =>
{
webHost.UseTestServer()
.UseStartup<TestStartup>()
.ConfigureLogging((hostBuilderContext, logging) =>
{
logging.Services.AddSingleton<ILoggerProvider, NUnitLoggerProvider>();
});
});
And instead of Debug.WriteLine(message) you can use something else to log to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With