微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在C#AspNet Core中模拟LoggerFactory

我正在尝试为控制器操作编写一些单元测试.为此,我使用XUnit和Moq.控制器在构造函数中注入ILoggerFactory.一个Moq如何进行测试?

我已经尝试为控制器类模拟一个Logger,然后模拟CreateLogger以返回模拟Logger,但是当调用Loginformation()函数时,我不断获得各种测试运行时NullReferenceExceptions.

//   Logger that yields only disappointment...          
        var mockLogger = new Mock<ILogger<JwtController>>();
        mockLogger.Setup(ml => ml.Log(It.IsAny<LogLevel>(),It.IsAny<EventId>(),It.IsAny<object>(),It.IsAny<Exception>(),It.IsAny<Func<object,Exception,string>>()));
        var mockLoggerFactory = new Mock<ILoggerFactory>();
        mockLoggerFactory.Setup(mlf => mlf.CreateLogger("JwtController")).Returns(mockLogger.Object);

我假设问题是正在调用Loginformation,这是一个扩展方法,那么如何moq呢?

解决方法

对于需要回答这个问题的人,而不是一个解决方法,我扩展了本文的工作:

https://ardalis.com/testing-logging-in-aspnet-core

包装您使用的日志框架的任何部分,无论如何这是一个好主意.从您自己的日志记录界面开始:

public interface ILog<T>
{
    void LogError(Exception ex,string message,params object[] args);
    void Loginformation(string message,params object[] args);
}

然后添加实现以传递对框架的调用

public class Log<T> : ILog<T>
{
    private readonly ILogger<T> logger;

    public Log(ILogger<T> logger)
    {
        this.logger = logger;
    }

    public void LogError(Exception ex,params object[] args) => this.logger.LogError(ex,message,args);
    public void Loginformation(string message,params object[] args) => this.logger.Loginformation(message,args);
}

继续,添加一个用于包装记录器工厂的接口:

public interface ILogFactory
{
    ILog<T> CreateLog<T>();
}

并实施:

public class LogFactory : ILogFactory
{
    private readonly ILoggerFactory loggerFactory;

    public LogFactory()
    {
        this.loggerFactory = new LoggerFactory();
    }

    public ILog<T> CreateLog<T>() => new Log<T>(new Logger<T>(this.loggerFactory));
}

这些是您应该引用Microsoft.Extensions.Logging命名空间的唯一地方.在其他地方,使用您的ILog< T>而不是ILogger< T>和你的ILogFactory而不是ILoggerFactory.你通常依赖注入LoggerFactory,而不是注入包装器:

IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ILogFactory>(new LogFactory());

在主代码中,您可以检索此LogFactory并创建特定的Log< T>为你的班级:

public class MyClass
{
    public void MyMethod(IServiceCollection serviceCollection)
    {
        var serviceProvider = serviceCollection.BuildServiceProvider();
        var logFactory = this.serviceProvider.GetrequiredService<ILogFactory>();
        var log = logFactory.CreateLog<ServiceApplication>();
        log.Loginformation("Hello,World!");
    }
}

您可以想象将MyMethod的参数从IServiceCollection更改为ILogFactory或ILog< MyClass>按要求.并且 – 重点是 – 您现在可以使用以下方法模拟上述代码

[Fact]
public void test()
{
    IServiceCollection serviceCollection = new ServiceCollection();
    var mockLog = new Mock<ILog<MyClass>>();
    var mockLogFactory = new Mock<ILogFactory>();
    mockLogFactory.Setup(f => f.CreateLog<MyClass>()).Returns(mockLog.Object);
    serviceCollection.AddSingleton<ILogFactory>(mockLogFactory.Object);

    var myClass = new MyClass();
    myClass.MyMethod(serviceCollection);

    mockLog.Verify(l => l.Loginformation("Hello,World!"),Times.Once);
}

“根据您在整个应用程序中无法控制的类型,会增加耦合,并且经常成为问题和技术债务的来源.” – 史蒂夫史密斯

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


本文将从上往下,循序渐进的介绍一系列相关.NET的概念,先从类型系统开始讲起,我将通过跨语言操作这个例子来逐渐引入一系列.NET的相关概念,这主要包括:CLS、...
基于 .NET 的一个全新的、好用的 PHP SDK + Runtime: PeachPie 来啦!
.NET 异步工作原理介绍。
引子 .NET 6 开始初步引入 PGO。PGO 即 Profile Guided Optimization,通过收集运行时信息来指导 JIT 如何优化代码,相比以前没有 PGO 时可以做更多以前难以
前言 2021/4/8 .NET 6 Preview 3 发布,这个版本的改进大多来自于底层,一起来看看都有什么新特性和改进吧。 库改进 新增值类型作为字典值时更快的处理方法 .NET 6 Previ
前言 开头防杠:.NET 的基础库、语言、运行时团队从来都是相互独立各自更新的,.NET 6 在基础库、运行时上同样做了非常多的改进,不过本文仅仅介绍语言部分。 距离上次介绍 C# 10 的特性已经有
直接使用 CIL - .NET 上的汇编语言编写 .NET Standard 类库
前言 不知不觉中,.NET Framework 已经更新到 4.8,.NET Core 也更新到了 3.0 版本。那么 .NET 的未来怎么样呢? 计划 2019 年 Build 大会上,微软宣布下一
本文带你穿越到未来一起看看未来的 C# 到底长什么样子。
前言 TypedocConverter 是我先前因帮助维护 monaco-editor-uwp 但苦于 monaco editor 的 API 实在太多,手写 C# 的类型绑定十分不划算而发起的一个项