Unit Testing Umami .. .Net Logging im ASP ,. .NET Core
Einleitung
Ich bin ein relativer Noob, der Moq benutzt und Moq verwendet.(.Yes IM'.m sich der Kontroversen bewusst ist und ich habe versucht, einen neuen Service zu testen.IM'.m hinzufügen, um Umami.....Net.,.umamiData.MSC7. Dies ist ein Dienst, mit dem ich Daten aus meiner Umami-Instanz ziehen kann, um in Sachen wie die Sortierung von Posts durch Popularität usw. zu verwenden.
Das Problem
Ich habe versucht, einen einfachen Test für die Login-Funktion hinzuzufügen, die ich beim Ziehen von Daten verwenden muss.
Wie Sie es sehen können, ist ein einfacher Dienst, der einen Benutzernamen und Passwort an die /api/auth/login Endpoint und bekommt ein Ergebnis...... Wenn das Ergebnis erfolgreich ist, speichert es den Token in der _token Feld und setzt die Authorization Kopfzeile für die HttpClient in zukünftigen Anfragen zu verwenden
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;
}
}
Nun wollte ich auch gegen den Logger testen, um sicherzustellen, dass es die korrekte messages logging. Microsoft.Extensions.Logging namespace und ich wollten testen, dass die richtigen Log-Nachrichten auf den Logger geschrieben wurden.
In Moq gibt es ein BUNCH der Pfosten um das Testen des Loggings sie alle haben diese grundlegende Form ( von https-://-adamstorr..-co-.-uk-MSC5-blogs-Mocking--ilogger.- mit --moq-MS K10
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;
}
WIE auch immer aufgrund von Moq-' , die jüngsten Änderungen ,( ,It , . , IsAnyType ist jetzt obsolet , und ASP-. ,NET Core , ' , Änderungen in FormattedLogValues Ich hatte eine harte Zeit bekommen diese zu arbeiten , um . ,
Ich versuchte ein BUNCH von Versionen und Varianten, aber es immer fehlgeschlagen , . , So ,... , ich gab auf , . ,
Die Lösung
So las ich eine Reihe von GitHub Nachrichten, die ich auf einen Beitrag von David Fowler stieß.('my ehemaliger Kollege und jetzt der Herr von -. ,NET ,)' was zeigte einen einfachen Weg zum Testen der Protokollierung in ASP , . , NET Core , .'
Dabei wird die neu für mich Microsoft.Extensions.Diagnostics.Testing Verpackung welche einige wirklich nützliche Erweiterungen für das Testen des Loggings hat
Also statt all dem Moq Zeug habe ich gerade die Microsoft.Extensions.Diagnostics.Testing Paket und fügte hinzu, dass die folgenden zu meinen 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();
}
Sie sehen, dass dieses meine ServiceCollection aufstellt. FakeLogger<T> und stellt dann die UmamiData service mit dem Benutzernamen und Passwort Ich möchte verwenden, um (.so kann ich Testfehler.)..
Die Tests mit FakeLogger
Dann können meine Tests werden.
[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);
}
Wo du siehst, rufe ich einfach die GetServiceProvider Methode, um meinen Service-Provider zu erhalten. AuthService und ILogger<AuthService> von dem Dienstleister
Weil ich diese als FakeLogger<T> Ich kann dann auf die FakeLogCollector und FakeLogRecord um die Protokolle zu erhalten und sie zu überprüfen
Dann kann ich einfach die Protokolle nach den richtigen Nachrichten überprüfen.
Schlussfolgerung
So dort haben Sie es.,... eine einfache Möglichkeit, Protokollmeldungen in Unit Tests ohne den Moq-Unsinn zu testen.