ste*_*eee 6 c# mocking ilogger
我有一个类级别的 ILogger,它是在构造函数中使用 ILoggerFactory 设置的。然后在该类的方法中使用记录器,效果非常好。
我正在努力研究如何模拟 ILogger 和 ILoggerFactory,以便我可以对 LogError 消息进行单元测试。谁能给我举个例子吗?
我使用 xUnit 和 Microsoft.Extentions.Logging 进行登录
//This is my unit test project
[Fact]
public void TestLogErrorMessage()
{
MyClass myClass = new MyClass (MockLoggerFactory().Object);
var result = myClass.Mymethod("a")
//How do I test the LogError message???
}
//Not sure if this is correct
private Mock<ILoggerFactory> MockLoggerFactory()
{
Mock<ILoggerFactory> mockLoggerFactory = new
Mock<ILoggerFactory>(MockBehavior.Default);
mockLoggerFactory.Setup(x => x.CreateLogger(It.IsAny<string>()))
.Returns(MockLogger().Object);
return mockLoggerFactory;
}
private Mock<ILogger> MockLogger()
{
var logger = new Mock<ILogger>();
return logger;
}
Run Code Online (Sandbox Code Playgroud)
//This is the class/method i need to test
private readonly ILogger logger;
public MyClass(ILoggerFactory loggerFactory)
{
if (loggerFactory != null)
{
this.logger = loggerFactory.CreateLogger<MyClass>();
}
}
public string Mymethod(string msg)
{
if(msg = "a")
{
this.logger.LogError($"error");
}
return "a string";
}
Run Code Online (Sandbox Code Playgroud)
小智 7
这最终对我有用,成功验证了LogError呼叫:
var loggerMock = new Mock<ILogger>();
Expression<Action<ILogger>> logAction = x =>
// You can change this up with other severity levels:
x.Log<It.IsAnyType>(LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>());
loggerMock.Setup(logAction).Verifiable();
// Call a method that calls LogError here.
loggerMock.Object.LogError("test");
loggerMock.Verify(logAction, Times.Once);
Run Code Online (Sandbox Code Playgroud)
你可以做这样的事情
(注意:这在这种特定情况下不起作用,因为它LogError是一种扩展方法,请参阅下面的更新):
Mock<ILogger> _logger; // declare it somewhere where your test can access it
[Fact]
public void TestLogErrorMessage()
{
MyClass myClass = new MyClass(MockLoggerFactory().Object);
var result = myClass.Mymethod("a")
_logger.Verify();
}
private Mock<ILoggerFactory> MockLoggerFactory()
{
_logger = new Mock<ILogger>();
_logger.Setup(log => log.LogError(It.IsAny<string>())).Verifiable();
Mock<ILoggerFactory> mockLoggerFactory = new Mock<ILoggerFactory>(MockBehavior.Default);
mockLoggerFactory.Setup(x => x.CreateLogger(It.IsAny<string>()))
.Returns(_logger.Object);
return mockLoggerFactory;
}
Run Code Online (Sandbox Code Playgroud)
需要注意的关键是Verifiable()设置ILogger模拟后的调用。Verifiable()您可以在这个问题中阅读更多内容。测试运行后,您可以通过调用.Verify()模拟来检查该方法是否被调用。
根据您的需要,您可以在测试类的构造函数中进行设置(如果您需要它进行所有/大多数测试)或直接在测试方法中进行设置。您也可以将其与ILoggerFactory. 关键是要保留记录器,以便您可以验证该方法是否被调用。
对于您的特定情况(尝试验证对的调用ILogger.LogError),您不能模拟LogError,而是底层方法ILogger.Log。这可能看起来像这样:
var formatter = new Func<It.IsAnyType, Exception, string>((a, b) => "");
m.Setup(x => x.Log<It.IsAnyType>(LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
formatter))
.Verifiable();
Run Code Online (Sandbox Code Playgroud)
另一种选择是制作一个假实现ILogger并从以下位置返回Mock<ILoggerFactory>:
mockLoggerFactory.Setup(_ => _.CreateLogger(It.IsAny<string>())
.Returns(new FakeLogger());
public class FakeLogger : ILogger
{
public static bool LogErrorCalled { get; set; }
public IDisposable BeginScope<TState>(TState state)
{
throw new NotImplementedException();
}
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if(logLevel == LogLevel.Error)
{
LogErrorCalled = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后在测试后您可以检查是否FakeLogger.LogErrorCalled是true。这针对您的特定测试进行了简化 - 当然您可以得到比这更详细的结果。
| 归档时间: |
|
| 查看次数: |
5123 次 |
| 最近记录: |