[英]Mocking and testing the LogError message using Moq and xUnit
我有一个 class 级别的 ILogger,它是在构造函数中使用 ILoggerFactory 设置的。 然后在该 class 中的方法中使用记录器,这非常有效。
我正在努力研究如何模拟 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;
}
//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";
}
这最终对我有用,成功验证了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);
你可以做这样的事情
(注意:这在这种特定情况下不起作用,因为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;
}
需要注意的关键是在设置ILogger
模拟之后对Verifiable()
的调用。 您可以在这个 SO question中阅读有关Verifiable()
的更多信息。 测试运行后,您可以通过在模拟上调用.Verify()
来检查该方法是否被调用。
根据您的需要,您可以在测试 class 的构造函数中进行设置(如果所有/大多数测试都需要它)或直接在测试方法中进行设置。 您也可以将它与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();
另一种选择是制作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;
}
}
}
然后在您的测试之后,您可以检查FakeLogger.LogErrorCalled
是否为true
。 这已针对您的特定测试进行了简化-您当然可以比这更详细。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.