# Unit Testing Umami.Net | - | Logger in i ASP |. | Net Core

# Inleiding

I' är en relaterad noob som använder Moq ( ja I ' är medveten om kontroversernaM SK3 och jag försökte testa en ny tjänst I' lägger till UmamiMska5 NetM Ska6 UmamiData Mska7 Det här är en tjänst som låter mig dra data från min Umami instans för att använda det i saker som att sortera poster efter popularitet och så vidare

[TOC]

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

# Problemet

Jag försökte lägga till en enkel test för den loginfunktion jag behöver använda när jag drar data.
Som ni ser är ' en enkel tjänst som skickar ut ett användarnamn och ett lösenord till `/api/auth/login` slutpunkt och får ett resultat. Om resultatet är lyckat så lagrar den token i `_token` och sätter `Authorization` header för `HttpClient` att använda i framtida begäran.

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

Nu ville jag också testa mot loggeren för att se till att den registrerade de korrekta meddelandena. `Microsoft.Extensions.Logging` Namespace och jag ville testa att de korrekta logsignalerna skrevs till logaren

I Moq finns det ♪ ' ♪ en BUNCH av poster kring testloggning de har alla den här grundformen ♪( ♪ från https ♪ :// ♪ Adamstorr ♪ МSK3 ♪ ko ♪ m. ♪ kuk ♪M/ ♪ blogg ♪ M/ ♪ mocking ♪ - ♪ logger ♪ - ♪ med - ♪ 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;
}
```

Hursomhelst på grund av Moqs senaste ändringar (It.IsAnyType är nu föråldrade ) och ASPs förändringar i formaterade logvaler I var det svårt att få det här att fungera

Jag försökte en BUCH av versioner och varianter men det misslyckades alltid.

# Lösningen

Så när jag läste en massa GitHub- meddelanden, stötte jag på en artikel av David Fowler ( min tidigare kollega och nu Lord of .NET) som visade ett enkelt sätt att testa inlogning i ASP
Det här använder *ny för mig* `Microsoft.Extensions.Diagnostics.Testing` [paket](https://github.com/dotnet/extensions/tree/main/src/Libraries/Microsoft.Extensions.Diagnostics.Testing) som har några riktigt användbara utlängningar för att testa logning.

Så istället för alla Moq-grejer så lade jag bara till `Microsoft.Extensions.Diagnostics.Testing` och lade följande till mina tester.

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

Du kommer att se att detta konfigurerar min ServiceCollection `FakeLogger<T>` och sedan sätter upp `UmamiData` service med username och password som jag vill använda ( så att jag kan testa misslyckanden

## Testen med FakeLogger

Då kan mina tester bli ":".

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

Där du ser "'", så ska jag bara ringa `GetServiceProvider` sättet att få min leverantör av tjänster, sedan få `AuthService` och `ILogger<AuthService>` från serviceleverantören.

Eftersom jag har dessa uppbyggda som `FakeLogger<T>` Jag kan sedan komma till `FakeLogCollector` och `FakeLogRecord` att få in logerna och kolla dem

Då kan jag helt enkelt kolla in logerna för de korrekta meddelandena.

# I slutsats

Så där har du det, ett enkelt sätt att testa logmeddelanden i Unittest utan Moq nonsens