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