C# 使用Moq和xUnit模拟和测试LogError消息

C# 使用Moq和xUnit模拟和测试LogError消息,c#,mocking,ilogger,C#,Mocking,Ilogger,我有一个类级ILogger,它是用构造函数中的ILogger工厂设置的。然后在该类中的一个方法中使用记录器,这非常有效 我正在努力研究如何模拟ILogger和ILogger工厂,以便对LogError消息进行单元测试。有人能给我举个例子吗 我正在使用xUnit和Microsoft.Extensions.Logging进行日志记录 //This is my unit test project [Fact] public void TestLogErrorMessage() { MyClass my

我有一个类级ILogger,它是用构造函数中的ILogger工厂设置的。然后在该类中的一个方法中使用记录器,这非常有效

我正在努力研究如何模拟ILogger和ILogger工厂,以便对LogError消息进行单元测试。有人能给我举个例子吗

我正在使用xUnit和Microsoft.Extensions.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;
}
//这是我的单元测试项目
[事实]
public void TestLogErrorMessage()
{
MyClass MyClass=新的MyClass(MockLoggerFactory().Object);
var result=myClass.Mymethod(“a”)
//如何测试日志错误消息???
}
//不确定这是否正确
私有模拟MockLoggerFactory()
{
Mock mockLoggerFactory=新建
Mock(MockBehavior.Default);
mockLoggerFactory.Setup(x=>x.CreateLogger(It.IsAny()))
.Returns(MockLogger().Object);
返厂;
}
私有模拟记录器()
{        
var logger=newmock();
返回记录器;
}

//这是我需要测试的类/方法
专用只读ILogger记录器;
公共MyClass(iLogger工厂loggerFactory)
{
if(loggerFactory!=null)
{
this.logger=loggerFactory.CreateLogger();
}
}
公共字符串Mymethod(字符串消息)
{
如果(msg=“a”)
{
this.logger.LogError($“error”);
}
返回“字符串”;
}

您可以这样做

(注意:这在这种特定情况下不起作用,因为
LogError
是一种扩展方法,请参阅下面的更新):

另一种选择是对
ILogger
进行伪实现,并从
Mock
返回该实现:

mockLoggerFactory.Setup(=>quot.CreateLogger(It.IsAny())
.Returns(新FakeLogger());
公共类FakeLogger:ILogger
{
公共静态bool logerror调用{get;set;}
公共IDisposable BeginScope(州)
{
抛出新的NotImplementedException();
}
公共bool已启用(LogLevel LogLevel)=>true;
公共无效日志(日志级别、日志级别、事件ID、事件ID、TState状态、异常、函数格式化程序)
{
if(logLevel==logLevel.Error)
{
LogErrorCalled=true;
}
}
}

然后在测试后,您可以检查FakeLogger.LogErrorCalled是否为
true
。这对于您的特定测试是简化的-您当然可以得到更详细的说明。

非常感谢您的建议。但是我尝试了这一点,现在我在MockLoggerFactory方法中得到以下错误:System、 NotSupportedException:'扩展方法上的设置无效:log=>log.LogError(It.IsAny(),new[]{})'它在此行崩溃:_logger.setup(log=>log.LogError(It.IsAny())。可验证();啊,对了,
ILogger
几乎都是用扩展方法完成的。我会更新我的答案。我使用了你的FakeLogger解决方案,因为我不能在我们的Moq版本(4.8.1)上使用IsAnyType而且目前还没有升级到13.1的计划。FaelgGog解决方案起到了很好的效果!非常感谢你是一个明星!如果这回答了你的问题,考虑一下投票/接受它来解决你的问题。
//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";
 }
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;
} 
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();
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;
        }
    }
}