Back to "Unit Testing Umami.Net | - | Logger in i ASP |. | Net Core"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

ASP.NET Core xUnit

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

Wednesday, 04 September 2024

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

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.

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 ♪

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 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.

    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 ":".

    [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

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.