gpt4 book ai didi

c# - 使用 ILoggerProvider 进行单元测试

转载 作者:行者123 更新时间:2023-12-04 15:28:57 26 4
gpt4 key购买 nike

我的单元测试设置中有这样的代码:

IServiceCollection services = new ServiceCollection();
services.AddSingleton<IDependency, Dependency>();
services.AddLogging();
services.RemoveAll<ILoggerProvider>();
services.AddSingleton<ILoggerProvider, MyCustomProvider>(provider =>
{
var myDependency = provider.GetService<IDependency>();
return new MyCustomProvider(myDependency );
});
var serviceProvider = services.BuildServiceProvider();

var logger = serviceProvider.GetService<ILogger>();

当我运行这个 logger一片空白。

DI 工厂创建的 lambda MyCustomProvider永远不会被调用。 MyCustomProvider 的构造函数也不是也不是我创建的实现 ILogger 的类的构造函数.

我猜我错过了一个步骤来连​​接它。但是 .Net Core 1、2 和 3 之间存在很多相互矛盾的文档。

我需要做什么才能以 .Net Core 3 方式连接我的提供商? (这样我就可以得到一个使用它的 ILogger。)

笔记:
  • 我不叫LoggingBuilder.AddProvider .但是如果你看看 source code对于该分机,它只调用 AddSingleton ,这就是我所做的,但是有一个工厂。 (明白了 here 。)
  • 同样services.RemoveAll<ILoggerProvider>()与调用 ClearProviders 相同.
  • 我的目标是模拟将 ILogger 注入(inject)到类构造函数中。

  • 例如:
    public class SomeClass
    {
    public SomeClass(ILogger<SomeClass> logger)
    {
    // Do Stuff
    }
    }

    不知何故,这是在没有指明任何提供者的情况下完成的。我想让它在我的单元测试中是一样的。 (只需使用我的自定义提供程序。)

    最佳答案

    你的原因logger变量是 null在这个例子中是因为 ILogger实际上并未注册为服务。如果你看AddLogging的来源你可以看到它只注册 ILogger<>ILoggerFactory .如果您曾经尝试接受 ILogger而不是 ILogger<MyClass>通过 .NET Core DI,您将遇到以下异常*:

    System.InvalidOperationException: 'Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'Your.Service'



    基于此,您的测试代码存在缺陷,因为您从未收到过 ILogger首先。要查看您的代码实际上是否有效,请修改您的测试代码,使其检索 ILogger<SomeClass>反而。您的变量的结果将是非空的,并且您的提供者的构造函数中设置的断点将被命中:
    // Get*Required*Service won't throw
    var logger = serviceProvider.GetRequiredService<ILogger<Program>>();

    如果你想能够注入(inject) ILogger ,您需要使用默认类别名称单独注册它**:
    services.AddSingleton<ILoggerProvider, MyCustomProvider>(); // no need for lambda
    services.AddSingleton<ILogger>(sp =>
    sp.GetService<ILoggerFactory>().CreateLogger("Default")
    );

    以下内容现在都可以使用并使用您的自定义提供程序:
    var loggerA = serviceProvider.GetRequiredService<ILogger<Program>>();
    var loggerB = serviceProvider.GetRequiredService<ILogger>();

    我有自己的自定义提供程序/工厂/记录器,用于注入(inject) xUnit 的 ITestOutputHelper按照与您相同的注册模式进入自定义记录器,所以我从个人经验中知道这是有效的。但我也测试过你的特定代码是否有效(模拟我自己的 IDependency )——上面的代码被执行并在 MyCustomProvider 的构造函数中设置了断点和服务注册命中。此外,如果我将记录器注入(inject)到一个类中,它也会被命中(如预期的那样)。

    您的评论“不知何故这是在没有指明任何提供者的情况下完成的”是错误的,因为您实际上已经注册了一个提供者!但即使在清除所有提供程序且未添加新提供程序的情况下,您仍然会得到非空记录器。这是因为 LoggerFactory只是循环遍历每个提供程序以在它们周围构建一个新的记录器包装器。如果没有提供者,那么您基本上会得到一个无操作记录器。

    * 这很不幸,因为某些工具(如 R#)会建议将参数转换为基本类型 ILogger然后打破DI!

    ** 默认类别名称是必需的,因为没有通用类型参数传递给 ILoggerFactory.CreateLogger .对于通用 ILogger<T>类别名称始终是 T 的变体的名字——但我们显然没有得到非通用版本的名字。如果我不得不猜测,这可能就是他们不注册 ILogger 的实现的原因。默认情况下。

    关于c# - 使用 ILoggerProvider 进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61674945/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com