اختبار وحدة أوامري.شبكة -اختبار клиент أوامری
المقدمة
الآن لدي امامي.حزمة الإنترنت هناك بالطبع أريد أن أتأكد من أن كل شيء يعمل كما كان متوقعا.
ملاحظة: هذه ليست ' طريقة ' مثالية ' نوع المراسلة , إنها ' هي فقط الطريقة التي قمت بها أنا ' أنا فعلتها حالياً . في الواقع أنا لا أحتاج ' حقاً لتحريك IHttpMessageHandler هنا يمكنك الهجوم على مسند رسالة الإتصال إلى مستخدم Http عادي للقيام بهذا. أردت فقط أن أريكم كيف يمكنك القيام بذلك مع ماك
اختبار وحدة
التجريب بالوحدات يشير إلى عملية اختبار وحدة واحدة من البرمجة للتأكد من أنها تعمل كما هو متوقع.
بالنسبة لحزمة مثل Umami.Net هذا معقد نوعا ما لأنها تتصل بمستخدم بعيد HttpClient ولديه IHostedService يستخدم لجعل إرسال بيانات الأحداث الجديدة سلسة قدر الإمكان.
اختبار UmamiClient
الجزء الأكبر من الاختبار HttpClient مكتبة مبنية على avoiding the actual 'HttpClientM SK1 call. This is done by creating a HttpClient التي تستخدم HttpMessageHandler الذي يعيد استجابة معروفة. هذا يتم عن طريق إنشاء HttpClient مع HttpMessageHandler الذي يعيد استجابة معروفة ; في هذه الحالة أقوم فقط بإعادة الاستجابة الواردة والتأكد من أن ' لم ينسق من قبل 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;
}
كما ترون، سيقوم هذا بإعداد Mock<HttpMessageHandler> ثم أنتقل إلى UmamiClient.
في هذا الرمز أربط هذا في IServiceCollection طريقة الإعداد. هذا يضيف كل الخدمات المطلوبة من قبل UmamiClient بما في ذلك HttpMessageHandler ومن ثم يعيد IServiceCollection للاستعمال في الإختبارات.
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;
}
لإستخدام هذا وحقنه في UmamiClient ثم أستخدم هذه الخدمات في UmamiClient الإعداد.
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>();
}
سوف ترون أن لدي هنا مجموعة من العوامل الإختيارية البديلة التي تسمح لي بإدخال خيارات مختلفة لمختلف أنواع الاختبار
الإختبارات
إذن الآن لدي كل هذا الإعداد في مكاني يمكنني الآن أن أبدأ كتابة الإختبارات UmamiClient الطرق.
أرسل
ما يعنيه كل هذا الإعداد هو أن اختباراتنا في الواقع يمكن أن تكون بسيطة جداً
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);
}
}
هنا ترون أبسط حالت الاختبار, فقط من أجل ضمان أن UmamiClient يمكننا إرسال رسالة والحصول على استجابة; بشكل مهم نحن أيضا نختبر حالة إستثناء حيث type هو خطأ. هذا جزء غالبا ما يتجاهله في الاختبار, للتأكد من أن الشفرة تفشل كما توقعت
رؤية الصفحة
لاختبار طريقتنا لرؤية الصفحات يمكننا القيام بشيء مماثل. في الشفرة التالية أستخدم EchoHttpHandler لتعكس ردة الفعل التي أرسلتها وتتأكد من أن تبعث ما أتوقعه
[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);
}
مُصل للمحتوى HttpContext
هذا يستخدم HttpContextAccessor لتحديد الطريق إلى /testpath ومن ثم يتأكد من أن UmamiClient يرسل هذا بشكل صحيح.
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;
}
هذا مهم بالنسبة لبرمجة زميلي Umami لأن الكثير من البيانات التي ترسل من كل طلب في الواقع يتم توليدها ديناميكيا من HttpContext object. إذن لا يمكننا إرسال أي شيء على الإطلاق في await umamiClient.TrackPageView(); وترسل البيانات الصحيحة عن طريق استخراج ال Url من HttpContext.
كما سنرى لاحقاً هو أيضاً مهم أن ترسل الأشياء مثل UserAgent و IPAddress كما أن هذه تستخدم من قبل server Umami لمتابعة البيانات و 'track' مشاهد المستخدم بدون استخدام cookiesM SK2
من أجل الحصول على هذا التنبؤ يمكننا تعريف مجموعة من المحافظات في Consts class. لذا يمكننا اختبارها ضد الاستجابات المتوقعة والطلبات
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";
}
اختبارات أخرى
هذا فقط بداية استراتيجية اختبارنا لـ Umami.Net, لا يزال علينا اختبار IHostedService واختبارها ضد البيانات الحقيقية ينتج "umami" ( والذي لا يتم وثيقه في أي مكان بل يحتوي على رمز JWT مع بعض البيانات المفيدة
{
"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
لذا سنريد ' أن نختبر ذلك , نحاكي الرموز وربما نعيد البيانات في كل زيارة uuid(websiteId,ipaddress, useragent)).
في الختام
هذا فقط بداية اختبار التجزئة الشبكية Umami., هنالك' هناك الكثير لفعله لكن هذا هو البداية الجيدة . سأقوم بإضافة المزيد من الإختبارات كلما ذهبت ولا شك في تحسين هذه