Eenheidstest Umami.Net - Loggen in ASPM SK2NET Core
Inleiding
Ik'm een relatieve noob met Moq (ja I'm aware of er controversieën zijn) en ik probeerde een nieuw service te testen I'n Addition to UmamiM SK5Net , UmamiDataMSC7 Dit is een dienst waarmee ik gegevens uit mijn Umami-instance kan halen om ze in dingen als het sorteren van posten volgens populariteit etc. te gebruiken
Het probleem
Ik probeerde een eenvoudige test voor de aantekenfunctie toe te voegen die ik nodig heb bij het trekken van data.
Zoals je ziet, is ' een eenvoudige dienst die een gebruiksnaam en wachtwoord aan de /api/auth/login en krijgt een resultaat. Als het resultaat succesvol is, zet hij de token op. _token Het veld en zet de Authorization hoofdletter voor de HttpClient om in toekomstige verzoeken te gebruiken.
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 wilde ik ook testen tegen de logger om er zeker van te zijn dat hij de juiste boodschappen inlogde. Microsoft.Extensions.Logging namespace en ik wilde testen dat de juiste logberichten werden geschreven aan de logger.
In Moq is er een BUNCH van posten rond het testen van logs ze hebben allemaal deze basisvorm (van httpsM SK2adamstorr.co .ukMSC5blogMST6mockingMst7iloggerM st8metMSt9moqMt10
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;
}
Maar door de recente veranderingen van Moq', (ItM SK2IsAnyType is nu verouderd ) en ASPMska4Net CoreMske5, de veranderingen naar geformateerde logwaarden Ik had het moeilijk om dit te laten werken.
Ik probeerde een paar versies en varianten, maar het mislukte altijd.
De oplossing
Dus door een hoop GitHub-berichten te lezen, kwam ik op een post van David Fowler tegen ( mijn voormalige collega en nu de heer van .NET) die een eenvoudige manier toonde om in ASP te testen.
Dit gebruikt de nieuw voor mij. Microsoft.Extensions.Diagnostics.Testing Paket Het heeft wat nuttige uitbreidingen voor het testen van logingen.
Dus in plaats van alle Moq-dingen voegde ik gewoon de Microsoft.Extensions.Diagnostics.Testing Ik voegde de volgende toe aan mijn tests.
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();
}
Je zal zien dat dit mijn ServiceCollection opstelt. FakeLogger<T> En dan maakt hij het UmamiData service met de gebruikernaam en wachtwoord die ik wil gebruiken.
De tests met FakeLogger
Dan kunnen mijn tests : worden.
[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);
}
Waar je het ziet, bel ik gewoon de GetServiceProvider methode om mijn dienstverlener, te krijgen en dan de AuthService en ILogger<AuthService> van de dienstverlener.
Want ik heb deze opgezet als FakeLogger<T> Ik kan dan toegang krijgen tot de FakeLogCollector en FakeLogRecord om de logs te krijgen en ze te controleren.
Dan kan ik gewoon de logs checken voor de juiste berichten.
In slotting:
Dus daar heb je het, een eenvoudige manier om logberichten in eenheidstests te testen zonder Moq nonsens.