# Unit Testing Umami.Net - Logging in ASPM SK2NET Core

# Introduzione

I' sono un noob relativo che usa Moq (sì I ' sono consapevole delle controversieM SK3 e stavo provando a testare un nuovo servizio I' sto aggiungendo ad UmamiMSC5NetMST6 UmamiDataMst7 Questo è un servizio che mi permette di estrarre dati dalla mia Instance Umami per usarli in cose come la classificazione dei post secondo la popolarità, ecc.

[TOC]

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

# Il problema

Stavo cercando di aggiungere un semplice test per la funzione di login che devo usare quando tiro i dati.
Come potete vedere' è un semplice servizio che passa un username e una password al `/api/auth/login` e ottiene un risultato. Se il risultato è riuscito si conserva il tocco nel `_token` e mette il campo. `Authorization` il titolo per la `HttpClient` per usare in future richieste.

```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;
    }
}
```

Ora volevo anche testare contro il loger per essere sicuri che stava registrando i messaggi corretti. I'm usando la `Microsoft.Extensions.Logging` namespace e volevo verificare se i messaggi corretti erano stati scritti al logr.

In Moq, c'è una BUNCH di posti per testare l'affidamento che hanno tutti questa forma di base (a partire da https://adamstorrM SK3coMSC4ukMスク5blog /mockingMST7iloggerMst8conMSt9moqM st10

```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;
}
```

Tuttavia, a causa dei recenti cambiamenti di Moq'(ItM SK2IsAnyType è ora obsoleto ) e ASPMスク4NET CoreMSC5Migrazioni alle Valide Log Formatate Ho avuto un po' di difficoltà a farcela funzionareMST6

Ho provato una BUNCH di versioni e varianti ma è sempre fallito. Così...Ho abbandonatoM SK2

# La soluzione

Quindi leggendo un sacco di messaggi su GitHub mi sono imbattuto in un post di David Fowler (il mio ex collega e ora Lord of .NET) che mostrava un modo semplice per testare l'affidamento nell' ASPM SK3NET CoreMSC4
Si usa la *per me nuova.* `Microsoft.Extensions.Diagnostics.Testing` [un pacco.](https://github.com/dotnet/extensions/tree/main/src/Libraries/Microsoft.Extensions.Diagnostics.Testing) che ha delle estenzioni molto utili per testare logging.

Quindi invece di tutte le cose Moq ho aggiunto `Microsoft.Extensions.Diagnostics.Testing` e ho aggiunto il seguente ai miei test.

```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();
        
    }
```

Voi' vedrete che questo configura il mio ServiceCollection, aggiunge la nuova `FakeLogger<T>` e poi mette in piedi la `UmamiData` il servizio con il nome di usuario e password che voglio usare ( così posso testare l'errore).

## I test usando FakeLogger

Allora i miei test possono diventare:

```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);
    }
```

Dove ve lo vedrete io semplicemente chiamo il `GetServiceProvider` Il metodo per ottenere il mio prestatore di servizi, e poi ottenere `AuthService` e `ILogger<AuthService>` dal prestatore di servizi.

Perché queste sono state create come `FakeLogger<T>` Posso poi accedere al `FakeLogCollector` e `FakeLogRecord` per prendere i log e controllarli.

Poi posso semplicemente controllare i log per trovare i messaggi corretti.

# Conclusione

Quindi eccolo qui, un modo semplice per testare i messaggi di log in Unit Tests senza il nonsenso Moq.