【发布时间】:2019-12-05 05:16:25
【问题描述】:
我们有一个相当简单的 netstandard2.0 自定义中间件项目,它使用 Serilog 的静态 LogContext 将指定的 HttpContext 标头复制到日志上下文。
我正在尝试编写一个单元测试,其中我设置了一个使用DelegatingSink 写入变量的记录器。然后它执行Invoke() 中间件方法。然后,我尝试使用该事件来断言已添加属性。到目前为止,中间件添加的属性没有显示,但我在测试中添加的属性会显示。我假设它正在处理不同的上下文,但我不确定如何解决这个问题。我尝试了几种不同的方法,但都没有奏效。
由于LogContext 是静态的,我认为这很简单,但我低估了一些东西。这就是我现在所处的位置(为简洁起见,省略了一些代码)。我确实确认了中间件的 LogContext.PushProperty 行 is 在其余部分运行时被击中。
测试:
...
[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 测试源中窃取的委托接收器:
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;
}
}
【问题讨论】:
标签: c# unit-testing serilog