繁体   English   中英

Mocking 并使用 Moq 和 xUnit 测试 LogError 消息

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM