【问题标题】:Implement full logging in Integration Test在集成测试中实现完整的日志记录
【发布时间】:2021-01-12 19:47:48
【问题描述】:

我正在 .Net Core 3.1 中创建一个新应用。

我已经创建了数据库,现在我正在处理业务逻辑,它位于服务集合中。在我开始创建 API 或 UI(即:任何网络应用程序类型的项目)之前,我希望 100% 让所有数据访问和服务首先按预期工作......包括日志记录。为了确保这一切都能正常工作,我想创建一些集成测试。

我遇到的问题是我真的很想知道如何让日志记录工作。我能找到的每个教程、文档和所有示例都假设您拥有 Program.csStartup.cs

注意 1: 我希望日志记录能够像在生产中一样工作,这意味着一直到 SQL。没有嘲讽。没有替代品。无需更换。

注意 2:我不太关心测试中的日志记录。我希望日志能够在服务中工作

这是我目前拥有的集成测试 (xUnit) 类的示例。它正在工作,但没有日志记录。

namespace MyApp.Test
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IAccountService, AccountService>();
            services.AddTransient<IAppSettings, AppSettings>();
        }
    }

    public class AccountServiceTests
    {
        private readonly IAccountService _account;
        private readonly IAppSettings _settings;

        public AccountServiceTests(IAccountService account, IAppSettings settings)
        {
            _account = account;
            _settings = settings;
        }

        [Fact]
        public async Task AccountService_CreateAccount()
        {
            Account account = new Account( {...} );
            bool result = _account.CreateAccount(account);
            Assert.True(result);
        }
    }
}

由于 NuGet Xunit.DependencyInjection,DI 正在工作。

然后在服务中...

public class AccountService : ServiceBase, IAccountService
{
        protected readonly ILogger _logger;
        protected readonly IAppSettings _settings;

        public AccountService(ILogger<AccountService> logger, IAppSettings settings) 
        {
            _logger = logger;
            _settings = settings;
        }

        public bool CreateAccount()
        {
            // do stuff
            _logger.Log(LogLevel.Information, "An account was created."); // I WANT THIS TO END UP IN SQL, EVEN FROM THE TEST.
        }
}

测试通过,并且在数据库中正确创建了帐户。然而,据我所知,这条线没有做任何事情:

_logger.Log(LogLevel.Information, "An account was created.");

我明白为什么。 Microsoft.Extensions.Logging 只是一个抽象,我需要实现一些具体的日志记录(用 SeriLog 或 Log4Net 等)

这让我回到了最初的问题:在我的一生中,我找不到关于如何让其中任何一个(SeriLog 或 Log4Net)在集成测试(尤其是 xUnit)中工作的工作教程。

任何帮助,或指向正确的方向,或指向教程的链接都会很棒。谢谢。

【问题讨论】:

  • 您好,Casey,我认为问题不在于缺少具体的记录器。相反,您可能需要在设置测试夹具时提供基本的日志记录配置。通常这可以通过在主机构建器上调用ConfigureLogging 来完成,但在这种特殊情况下我不确定。我的工作 PC 上没有可用的 .Net Core。我建议考虑在 .Net Core 控制台应用程序中设置日志记录。
  • @Amy,谢谢。我认为你是正确的。我完全没有在这方面找到任何东西,这让我觉得我找错了树。我需要一位专家来咨询。

标签: c# .net .net-core integration-testing .net-core-logging


【解决方案1】:

使用LoggingServiceCollectionExtensions.AddLogging向服务集合添加日志记录

public class Startup {
    public void ConfigureServices(IServiceCollection services) {
        services.AddLogging(builder => 
            builder.ClearProviders()
                .Add{ProverNameHere}()

            // ... other logging configuration
        );
        services.AddTransient<IAccountService, AccountService>();
        services.AddTransient<IAppSettings, AppSettings>();
    }
}

这将为ILogger&lt;&gt; 添加工厂并打开泛型,以便可以在需要的地方注入它们。

根据需要配置该信息应该去哪里的日志记录。

ASP.NET Core 将 built-in providers 作为共享框架的一部分包含在内,但由于这是一个独立的测试,您必须根据需要添加所需的提供程序。

例如

//...

services.AddLogging(builder => builder.AddConsole().AddDebug());

//...

控制台

控制台提供程序将输出记录到控制台。

调试

Debug 提供程序使用 System.Diagnostics.Debug 类写入日志输出。调用System.Diagnostics.Debug.WriteLine 写入Debug 提供程序。

dotnet run 和 Visual Studio 的日志输出

显示使用默认日志记录提供程序创建的日志:

  • 在 Visual Studio 中
    • 调试时在调试输出窗口中。
    • 在 ASP.NET Core Web 服务器窗口中。
  • 在使用 dotnet run 运行应用程序时的控制台窗口中。

以“Microsoft”类别开头的日志来自 ASP.NET Core 框架代码。 ASP.NET Core 和应用程序代码使用相同的日志记录 API 和提供程序。

参考:Logging in .NET Core and ASP.NET Core

【讨论】:

  • 知道了!我终于可以使用这个来查看日志:services.AddLogging(builder =&gt; builder.ClearProviders().AddDebug());。由于某种原因没有ClearProviders(),它不会写入输出窗口。现在它是。谢谢!
【解决方案2】:

配置一个记录器工厂

using var loggerFactory = LoggerFactory.Create(builder =>
{
    builder
        .AddFilter("Microsoft", LogLevel.Warning)
        .AddFilter("System", LogLevel.Warning)
        .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
        .AddConsole()
        .AddEventLog();
});

然后将其注册为服务

services.AddSingleton(loggerFactory);

【讨论】:

  • 马丁,谢谢!根据我的 OP 中的示例测试类,第一个代码块会去哪里?
  • 我对Xunit.DependencyInjection nugget不是很熟悉,但它可能会进入ConfigureServices方法。
  • System.AggregateException :发生了一个或多个错误。 (无法访问已处置的对象。对象名称:'LoggerFactory'。)(以下构造函数参数没有匹配的夹具数据:IAccountService 帐户、IAppSettings 设置)
  • @CaseyCrookston using 正在处置工厂。只需删除那一点。
  • 好的,现在测试运行没有错误,调用服务并创建帐户。那么现在的问题是,当我在服务中调用_logger.LogInformation() 时,我在哪里看到输出?
【解决方案3】:

如果您只想看到日志记录在 xUnit 中工作,请将以下代码添加到 xUnit 测试的构造函数中,然后将其传递给基本构造函数,如下所示。 (我假设您在这里使用 WebApplicationFactory 来启动测试中的服务。)

protected readonly WebApplicationFactory<Startup> Factory;

public AccountServiceTests(IAccountService account, IAppSettings settings, ITestOutputHelper testOutputHelper) : base( testOutputHelper )
{
    _account = account;
    _settings = settings;

    Factory = new WebApplicationFactory<Startup>().WithWebHostBuilder(builder =>
        {
            builder.ConfigureTestServices(services =>
            {
                services.AddLogging(logBuilder => logBuilder.AddXUnit(testOutputHelper));
            });
        });
}

这将导致您的日志消息显示在测试的输出中。

请注意,此处的详细信息可能会因您所拥有的内容而有所不同,但这是基本思想:xUnit 传入 testOutputHelper,然后您使用它来初始化日志记录系统以进行测试。

以编程方式验证您的测试是否写入了正确的日志消息是另一回事。我没有现成的答案。

【讨论】:

  • 谢谢马克,但我不想从测试中测试日志记录。我想在服务中对其进行测试。
  • @CaseyCrookston 但是您想在 xUnit 下运行服务时从服务内部测试日志记录,对吧?如果是这样,这就是你想要的。我正在修改我的答案以包括我忘记的另一个初始化步骤。
  • But you want to test logging from within the service while running the service under xUnit, right? 是的! 100% 正确!
  • 我收到"Factory" does not exist in the current context.
  • 对不起,这不完整。我刚刚为工厂字段添加了一个声明。
猜你喜欢
  • 2011-04-30
  • 2021-11-16
  • 1970-01-01
  • 2014-02-03
  • 1970-01-01
  • 2020-12-07
  • 1970-01-01
  • 2017-08-03
  • 1970-01-01
相关资源
最近更新 更多