gpt4 book ai didi

c# - 如何对 Serilog 的 LogContext 属性进行单元测试

转载 作者:太空宇宙 更新时间:2023-11-03 14:40:18 25 4
gpt4 key购买 nike

我们有一个相当简单的 netstandard2.0 自定义中间件项目,它使用 Serilog 的静态 LogContext 将指定的 HttpContext header 复制到日志上下文。

我正在尝试编写一个单元测试,我在其中设置了一个使用 DelegatingSink 写入变量的记录器。然后它执行 Invoke() 中间件方法。然后我尝试使用该事件来断言属性已添加。到目前为止,中间件添加的属性没有显示,但我在测试中添加的属性显示了。我假设它正在处理不同的上下文,但我不确定如何解决这个问题。我尝试了几种不同的方法,但都没有奏效。

由于 LogContext 是静态的,我认为这会非常简单,但我低估了某些东西。这就是我现在所在的位置(为简洁起见省略了一些代码)。我确实确认了中间件的 LogContext.PushProperty 在其余部分运行时被命中。

测试:

...
[Fact]
public async Task Adds_WidgetId_To_LogContext()
{
LogEvent lastEvent = null;

var log = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.Sink(new DelegatingSink(e => lastEvent = e))
.CreateLogger();
// tried with and without this, also tried the middleware class name
//.ForContext<HttpContextCorrelationHeadersLoggingMiddlewareTests>();

var context = await GetInvokedContext().ConfigureAwait(false);

LogContext.PushProperty("MyTestProperty", "my-value");

log.Information("test");

// At this point, 'lastEvent' only has the property "MyTestProperty" :(
}

private async Task<DefaultHttpContext> GetInvokedContext(bool withHeaders = true)
{
RequestDelegate next = async (innerContext) =>
await innerContext.Response
.WriteAsync("Test response.")
.ConfigureAwait(false);

var middleware = new MyCustomMiddleware(next, _options);

var context = new DefaultHttpContext();

if (withHeaders)
{
context.Request.Headers.Add(_options.WidgetIdKey, _widgetId);
}

await middleware.Invoke(context).ConfigureAwait(false);

return context;
}

中间件(测试项目引用本项目):

...
public async Task Invoke(HttpContext context)
{
if (context == null || context.Request.Headers.Count == 0) { await _next(context).ConfigureAwait(false); }

var headers = context.Request.Headers;

foreach (var keyName in KeyNames)
{
if (headers.ContainsKey(keyName))
{
LogContext.PushProperty(keyName, headers[keyName]);
}
}

await _next(context).ConfigureAwait(false);
}
...

这是我从 Serilog 测试源中窃取的委托(delegate)接收器:

public class DelegatingSink : ILogEventSink
{
readonly Action<LogEvent> _write;

public DelegatingSink(Action<LogEvent> write)
{
_write = write ?? throw new ArgumentNullException(nameof(write));
}

public void Emit(LogEvent logEvent)
{
_write(logEvent);
}

public static LogEvent GetLogEvent(Action<ILogger> writeAction)
{
LogEvent result = null;

var l = new LoggerConfiguration()
.WriteTo.Sink(new DelegatingSink(le => result = le))
.CreateLogger();

writeAction(l);

return result;
}
}

最佳答案

我还必须对已记录事件的推送属性进行单元测试。假设您正在插入您的属性(property)如下:

public async Task<T> FooAsync(/*...*/)
{
/*...*/
using (LogContext.PushProperty("foo", "bar"))
{
Log.Information("foobar");
}
/*...*/
}

您可以使用 Serilog.Sinks.TestCorrelator 像这个例子一样对其进行单元测试作为专用于测试的 Serilog 接收器(我在这里也使用 NUnitFluentAssertion):

[Test]
public async Task Should_assert_something()
{
///Arrange
// I had issues with unit test seeing log events from other tests running at the same time so I recreate context in each test now
using (TestCorrelator.CreateContext())
using (var logger = new LoggerConfiguration().WriteTo.Sink(new TestCorrelatorSink()).Enrich.FromLogContext().CreateLogger())
{
Log.Logger = logger;
/*...*/
/// Act
var xyz = await FooAsync(/*...*/)
/*...*/

/// Assert
TestCorrelator.GetLogEventsFromCurrentContext().Should().ContainSingle().Which.MessageTemplate.Text.Should().Be("foobar");
}
}

关于c# - 如何对 Serilog 的 LogContext 属性进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57227172/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com