Tar*_*Tar 3 c# dependency-injection moq mocking inversion-of-control
由于使用Moq不可能模拟开放泛型类型,因此创建实际的模拟是不可避免的。这是我最终使用的最小模拟:
internal interface ILoggerMock {
public List<(LogLevel logLevel, string msg)> Logs { get; }
}
public class LoggerMock<T> : ILoggerMock, ILogger<T> {
public List<(LogLevel logLevel, string msg)> Logs { get; } = new();
public IDisposable BeginScope<TState>(TState state) => throw new NotImplementedException();
public bool IsEnabled(LogLevel logLevel) => throw new NotImplementedException();
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) {
var formattedLogMessage = formatter(state, exception);
Logs.Add((logLevel, formattedLogMessage));
}
}
Run Code Online (Sandbox Code Playgroud)
通过此注册:
var myServiceProvider = new ServiceCollection()
// ... more registrations as needed ...
.AddSingleton(typeof(ILogger<>), typeof(LoggerMock<>))
// ... more registrations as needed ...
.BuildServiceProvider()
_loggerMock = (ILoggerMock) myServiceProvider.GetService(typeof(ILogger<Answer>));
Run Code Online (Sandbox Code Playgroud)
每个类都会注入每个类的ILogger<T>位置,例如:T
public class Question {
public Question(ILogger<Question> logger) { /* ... */ }
}
public class Answer {
public Answer(ILogger<Answer> logger) { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
但这意味着我必须为每个ILogger<T>消费者创建一个模拟:
var questionLoggerMock = new Mock<ILogger<Question>>();
var answerLoggerMock = new Mock<ILogger<Answer>>();
var services = new ServiceCollection()
.AddScoped<ILogger<Question>>(_ => questionLoggerMock.Object)
.AddScoped<ILogger<Answer>>(_ => answerLoggerMock.Object)
/*
.
... all other ILogger consumers...
.
*/
Run Code Online (Sandbox Code Playgroud)
我尝试了很多技巧,例如.AddSingleton<ILogger<object>>(_ => omniLoggerMock.Object)或.AddSingleton(typeof(ILogger<>), _ => omniLoggerMock.Object),但似乎都不起作用(如果编译,它们会在运行时失败)。
有没有一个简单的解决方案,或者我注定要为每个泛型类型创建一个新的模拟?
小智 5
如果您不需要测试/模拟调用,最简单的方法是使用NullLogger
services.Add(
ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(NullLogger<>)));
Run Code Online (Sandbox Code Playgroud)
如果您需要模拟部分,因为您需要查看是否记录了正确的内容,您可以这样做:
var mocker = new Mock<ILogger>();
services.Add(
ServiceDescriptor.Singleton(typeof(ILogger), mocker.Object));
services.Add(
ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(ProxyLogger<>)));
public class ProxyLogger<T>: ILogger<T>{
private readonly ILogger proxee;
public ProxyLogger(ILogger proxee)
{
this.proxee = proxee;
}
public IDisposable BeginScope<TState>(TState state)
=> proxee.BeginScope<TState>(state);
public bool IsEnabled(LogLevel logLevel)
=> proxee.IsEnabled(logLevel);
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
=> proxee.Log(logLevel, eventId, state, exception, formatter);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
448 次 |
| 最近记录: |