# 单位测试 Umami. @ Net @ -}在 ASP_.NET 核心中登录

# 一. 导言导言 导言 导言 导言

使用 Moq @(Yes IQ'注意到争议性@)}我正尝试测试新服务I'm,

[TOC]

<!--category-- xUnit, ASP.NET Core -->
<datetime class="hidden">2024-09-04T13:22</datetime>

# 问题

我试图添加一个简单的登录函数测试, 用于调用数据时需要使用的登录函数@ .
您可以看到它@' @%s 是一个简单的服务, 它传递用户名和密码到 `/api/auth/login` 如果结果成功, 它会将标记保存在 `_token` 字段设置 `Authorization` 和 `HttpClient` 用于未来请求@. @%

```csharp
public class AuthService(HttpClient httpClient, UmamiDataSettings umamiSettings, ILogger<AuthService> logger)
{
    private string _token = string.Empty;
    public HttpClient HttpClient => httpClient;

    public async Task<bool> LoginAsync()
    {
        var loginData = new
        {
            username = umamiSettings.Username,
            password = umamiSettings.Password
        };

        var content = new StringContent(JsonSerializer.Serialize(loginData), Encoding.UTF8, "application/json");
        var response = await httpClient.PostAsync("/api/auth/login", content);

        if (response.IsSuccessStatusCode)
        {
            var authResponse = await response.Content.ReadFromJsonAsync<AuthResponse>();

            if (authResponse == null)
            {
                logger.LogError("Login failed");
                return false;
            }

            _token = authResponse.Token;
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token);
            logger.LogInformation("Login successful");
            return true;
        }

        logger.LogError("Login failed");
        return false;
    }
}
```

现在,我还想对登录器进行测试,以确保它正在使用“% 1” 记录正确的信息@. @ I'}m `Microsoft.Extensions.Logging` 命名空间和我要测试正确的日志消息是否正在写入对帐簿@ .

在Moq 'ZQ的BUNCH中, 测试伐木周围的文章都有一个基本表单 @(}他们都有这个基本的表格: <https@://\adamtorr}.{co.ukMS K5>blog=/mocking-ilogger_-}与{-#moq}/)}

```csharp
public static Mock<ILogger<T>> VerifyDebugWasCalled<T>(this Mock<ILogger<T>> logger, string expectedMessage)
{
    Func<object, Type, bool> state = (v, t) => v.ToString().CompareTo(expectedMessage) == 0;
    
    logger.Verify(
        x => x.Log(
            It.Is<LogLevel>(l => l == LogLevel.Debug),
            It.IsAny<EventId>(),
            It.Is<It.IsAnyType>((v, t) => state(v, t)),
            It.IsAny<Exception>(),
            It.Is<Func<It.IsAnyType, Exception, string>>((v, t) => true)));

    return logger;
}
```

以及ASP=.NET Core@'}格式化LogValues的更改。 我很难让这个变换成功 *.*

我尝试过一个版本和变体的 BUNCH, 但总是失败了 @ . @ so..._I gave up@ MS K2}

# 解决方案

读了一大堆GitHub留言, 我遇见大卫·福勒(David Fowler)的一篇文章:“(@MSKO}我的前任同事,
此处使用 *对我而言全新的* `Microsoft.Extensions.Diagnostics.Testing` [软件包包](https://github.com/dotnet/extensions/tree/main/src/Libraries/Microsoft.Extensions.Diagnostics.Testing) 其中有一些用于测试日志的非常有用的扩展@ . @

而不是所有莫克人的东西 我刚刚加了 `Microsoft.Extensions.Diagnostics.Testing` 软件包,并在我的测试中添加了以下内容 @.

```csharp
    public IServiceProvider GetServiceProvider (string username="username", string password="password")
    {
        var services = new ServiceCollection();
        var mockLogger = new FakeLogger<UmamiDataService>();
        var authLogger = new FakeLogger<AuthService>();
        services.AddScoped<ILogger<UmamiDataService>>(_ => mockLogger);
        services.AddScoped<ILogger<AuthService>>(_ => authLogger);
        services.SetupUmamiData(username, password);
        return  services.BuildServiceProvider();
        
    }
```

您将看到这个设置我的服务 集合=,+#新的 `FakeLogger<T>` 然后制定, `UmamiData` 使用用户名和密码服务,我想使用“% (” 来测试失败吗?% 1}

## 使用假冒错误的测试

然后,我的测试可以变成:

```csharp
    [Fact]
    public async Task SetupTest_Good()
    {
        var serviceProvider = GetServiceProvider();
        var authService = serviceProvider.GetRequiredService<AuthService>();
        var authLogger = serviceProvider.GetRequiredService<ILogger<AuthService>>();
        var result = await authService.LoginAsync();
        var fakeLogger = (FakeLogger<AuthService>)authLogger;
        FakeLogCollector collector = fakeLogger.Collector; // Collector allows you to access the captured logs
         IReadOnlyList<FakeLogRecord> logs = collector.GetSnapshot();
         Assert.Contains("Login successful", logs.Select(x => x.Message));
        Assert.True(result);
    }
```

在那里你会看到,我只要叫 `GetServiceProvider` 获取服务提供方的方法 @,}然后获得 `AuthService` 和 `ILogger<AuthService>` 服务提供方@. @%

因为我有这些设置 `FakeLogger<T>` 然后我就可以进入 `FakeLogCollector` 和 `FakeLogRecord` 以获取日志并检查它们@. @%

然后我就可以简单地检查正确消息的日志@. @

# 在结论中的结论

这样你就可以用它来测试单数测试中的日志信息 而不使用莫克的无稽之谈 .