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
Eenheidstest Umami.Net -Testing UmamiClient
Sunday, 01 September 2024
Inleiding
Nu heb ik het Umami.Net pakket Daar wil ik natuurlijk zorgen dat het allemaal werkt zoals verwacht. Om dit te doen, is de beste manier om alle methoden en klasse een beetje grondig te testen.
Let op: Dit is geen 'perfecte aanpak ' typepostM SK4 het is ' precies hoe ik dit nu gedaan heb. IHttpMessageHandler Hier kun je een DelegatingMessageHandler aanvallen op een normale HttpClient om dit te doen.
Eenheidstest
Eenheidstest gaat over het proces van het testen van individuele eenheden van code om ervoor te zorgen dat ze werken zoals verwacht.
Voor een pakket als Umami.Net is dit nogal ingewikkeld, want het roept een afgeleë client op. HttpClient en heeft een IHostedService Het maakt het versturen van nieuwe gebeurtenisgegevens zo naadloos mogelijk..
Om UmamiClient te testen
Het grootste deel van het testen HttpClient Based library vermijdt de daadwerkelijke 'HttpClient' roepM SK2 Dit gebeurt door een HttpClient Die gebruikt een HttpMessageHandler Dat geeft terug een bekende reactie. Dit gebeurt door het maken van een HttpClient Met een HttpMessageHandler Dat geeft terug een bekende reactie;, in dit geval ik echo terug de inputreactie en controleer dat het niet gemanipuleerd is door de UmamiClient.
public static HttpMessageHandler Create()
{
var mockHandler = new Mock<HttpMessageHandler>();
mockHandler.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.Is<HttpRequestMessage>(x => x.RequestUri.ToString().Contains("api/send")),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync((HttpRequestMessage request, CancellationToken cancellationToken) =>
{
// Read the request content
var requestBody = request.Content != null
? request.Content.ReadAsStringAsync(cancellationToken).Result
: null;
// Create a response that echoes the request body
var responseContent = requestBody != null
? requestBody
: "No request body";
// Return the response
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(responseContent, Encoding.UTF8, "application/json")
};
});
return mockHandler.Object;
}
Zoals je ziet, maakt dit een Mock<HttpMessageHandler> Ik breng dan in. UmamiClient.
In deze code koppel ik dit aan onze computer. IServiceCollection Opstellingsmethode. Dit voegt alle diensten toe die nodig zijn bij de UmamiClient Inbegrip van onze nieuwe HttpMessageHandler Dan keert hij de cijfers terug. IServiceCollection voor gebruik in de tests.
public static IServiceCollection SetupServiceCollection(string webSiteId = Consts.WebSiteId,
string umamiPath = Consts.UmamiPath, HttpMessageHandler? handler = null)
{
var services = new ServiceCollection();
var umamiClientSettings = new UmamiClientSettings
{
WebsiteId = webSiteId,
UmamiPath = umamiPath
};
services.AddSingleton(umamiClientSettings);
services.AddScoped<PayloadService>();
services.AddLogging(x => x.AddConsole());
// Mocking HttpMessageHandler with Moq
var mockHandler = handler ?? EchoMockHandler.Create();
services.AddHttpClient<UmamiClient>((serviceProvider, client) =>
{
var umamiSettings = serviceProvider.GetRequiredService<UmamiClientSettings>();
client.BaseAddress = new Uri(umamiSettings.UmamiPath);
}).ConfigurePrimaryHttpMessageHandler(() => mockHandler);
return services;
}
Om dit te gebruiken en in te injecteren. UmamiClient Dan gebruik ik deze diensten in de UmamiClient opstelling.
public static UmamiClient GetUmamiClient(IServiceCollection? serviceCollection = null,
HttpContextAccessor? contextAccessor = null)
{
serviceCollection ??= SetupServiceCollection();
SetupUmamiClient(serviceCollection, contextAccessor);
if (serviceCollection == null) throw new NullReferenceException(nameof(serviceCollection));
var serviceProvider = serviceCollection.BuildServiceProvider();
return serviceProvider.GetRequiredService<UmamiClient>();
}
Je zal zien dat ik hier een hoop alternatieve opsionele parameters heb waardoor ik verschillende opties kan injecteren voor verschillende testtypen.
De tests
Dus nu heb ik al deze opstelling op de plaats Ik kan nu beginnen met het schrijven van toetsen voor UmamiClient methodes.
Stuur
Dit alles betekent dat onze tests eigenlijk vrij eenvoudig kunnen zijn.
public class UmamiClient_SendTests
{
[Fact]
public async Task Send_Wrong_Type()
{
var umamiClient = SetupExtensions.GetUmamiClient();
await Assert.ThrowsAsync<ArgumentException>(async () => await umamiClient.Send(type: "boop"));
}
[Fact]
public async Task Send_Empty_Success()
{
var umamiClient = SetupExtensions.GetUmamiClient();
var response = await umamiClient.Send();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
}
Hier zie je de eenvoudigste testcase, die ervoor zorgt dat het UmamiClient We kunnen een bericht sturen en een antwoord krijgen. type is verkeerd. Dit is een vaak over het hoofd gezien onderdeel van het testen, om te verzekeren dat de code niet werkt zoals verwacht.
Bladsy Besigtig
Om onze paginabeeldmethode te testen kunnen we iets gelijkaardigs doen. In de code onder gebruik ik mijn EchoHttpHandler om gewoon de gestuurde reactie terug te reflecteren en ervoor te zorgen dat het terug stuurt wat ik verwacht.
[Fact]
public async Task TrackPageView_WithNoUrl()
{
var defaultUrl = "/testpath";
var contextAccessor = SetupExtensions.SetupHttpContextAccessor(path: "/testpath");
var umamiClient = SetupExtensions.GetUmamiClient(contextAccessor: contextAccessor);
var response = await umamiClient.TrackPageView();
var content = await response.Content.ReadFromJsonAsync<EchoedRequest>();
Assert.NotNull(response);
Assert.NotNull(content);
Assert.Equal(content.Payload.Url, defaultUrl);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
HttpContextAccessor
Dit gebruikt de HttpContextAccessor om de weg te bepalen naar: /testpath Dan controleert hij dat de UmamiClient stuurt dit correct.
public static HttpContextAccessor SetupHttpContextAccessor(string host = Consts.Host,
string path = Consts.Path, string ip = Consts.Ip, string userAgent = Consts.UserAgent,
string referer = Consts.Referer)
{
HttpContext httpContext = new DefaultHttpContext();
httpContext.Request.Host = new HostString(host);
httpContext.Request.Path = new PathString(path);
httpContext.Connection.RemoteIpAddress = IPAddress.Parse(ip);
httpContext.Request.Headers.UserAgent = userAgent;
httpContext.Request.Headers.Referer = referer;
var context = new HttpContextAccessor { HttpContext = httpContext };
return context;
}
Dit is belangrijk voor onze Umami-kliëntcode omdat veel van de gegevens die uit elke verzoek worden gestuurd, dynamisch wordt geproduceerd vanuit de server. HttpContext object. Dus we kunnen niets sturen in een await umamiClient.TrackPageView(); Het stuurt nog steeds de juiste gegevens door het Url uit te halen. HttpContext.
Zoals we later zullen zien, is het ook belangrijk dat de verwondering dingen als deze sturen. UserAgent en IPAddress Deze worden gebruikt door de Umami server om de gegevens te volgen en 'track' gebruiker aansigten zonder cookies te gebruikenM SK2
Om dit voorspelbaar te hebben, definiëren we een aantal Konten in de Consts class. Zo kunnen we testen tegen voorspelbare reacties en verzoeken.
public class Consts
{
public const string UmamiPath = "https://example.com";
public const string WebSiteId = "B41A9964-FD33-4108-B6EC-9A6B68150763";
public const string Host = "example.com";
public const string Path = "/example";
public const string Ip = "127.0.0.1";
public const string UserAgent = "Test User Agent";
public const string Referer = "Test Referer";
public const string DefaultUrl = "/testpath";
public const string DefaultTitle = "Example Page";
public const string DefaultName = "RSS";
public const string DefaultType = "event";
public const string Email = "[email protected]";
public const string UserId = "11224456";
public const string UserName = "Test User";
public const string SessionId = "B41A9964-FD33-4108-B6EC-9A6B68150763";
}
Volgende testen
Dit is slechts het begin van onze teststrategie voor Umami.Net, we moeten nog steeds de IHostedService en testen tegen de feitelijke gegevens Umami genereert (, dat niet waar dan ook dokumenteerd is maar een JWT-token bevat met nuttige data.
{
"alg": "HS256",
"typ": "JWT"
}{
"id": "b9836672-feee-55c5-985a-a5a23d4a23ad",
"websiteId": "32c2aa31-b1ac-44c0-b8f3-ff1f50403bee",
"hostname": "example.com",
"browser": "chrome",
"os": "Windows 10",
"device": "desktop",
"screen": "1920x1080",
"language": "en-US",
"country": "GB",
"subdivision1": null,
"subdivision2": null,
"city": null,
"createdAt": "2024-09-01T09:26:14.418Z",
"visitId": "e7a6542f-671a-5573-ab32-45244474da47",
"iat": 1725182817
}2|Y*: �(N%-ޘ^1>@V
Dus we willen testen voor dat , het token simuleren en mogelijk de gegevens teruggeven bij elke bezoek. uuid(websiteId,ipaddress, useragent)).
In slotting:
Dit is nog maar het begin van het testen van de Umami-package.