# इकाई परीक्षण Umami.नेट - परीक्षण UmamClient

# परिचय

अब मेरे पास [उमामी.Net पैकेज](https://www.nuget.org/packages/Umami.Net/) वहाँ मैं निश्चित रूप से यह सुनिश्चित करना चाहता हूँ कि सभी अपेक्षित रूप में काम करता है
नोट: यह एक 'perfect दृष्टिकोण नहीं है। ' टाइप पोस्ट है। `IHttpMessageHandler` यहाँ एक आप इस करने के लिए एक सामान्य HttpClient को DelegatingMessageHandler पर हमला कर सकते हैं

[TOC]

<!--category-- xUnit, Umami -->
<datetime class="hidden">2024-09-01T17:22</datetime>

# इकाई परीक्षण

इकाई परीक्षण को कोड के अलग-अलग इकाइयों का परीक्षण करने की प्रक्रिया निर्दिष्ट करता है ताकि यह सुनिश्चित किया जा सके कि वे अपेक्षित रूप से काम करते हैं।

Umami.Net जैसे पैकेज के लिए यह बहुत जटिल है क्योंकि यह दोनों दूरस्थ क्लाइंट पर कॉल करता है `HttpClient` और एक है `IHostedService` यह नए घटना डेटा के भेजने को यथासंभव सीधा बनाता है

## UmamiClient का परीक्षण कर रहा है

एक परीक्षण का मुख्य भाग `HttpClient` आधारित लाइब्रेरी वास्तविक 'HttpClient' कॉल से बचता है `HttpClient` जो एक का उपयोग करता है `HttpMessageHandler` जो एक ज्ञात प्रतिक्रिया लौटाता है. यह एक बनाने के द्वारा किया जाता है `HttpClient` के साथ `HttpMessageHandler` जो एक ज्ञात प्रतिक्रिया को लौटाता है; इस मामले में मैं सिर्फ इनपुट प्रतिक्रिया के पीछे प्रतिध्वनित करता हूँ और यह जाँचें कि `UmamiClient`.

```csharp
    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` परीक्षणों में उपयोग के लिए

```csharp
    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` सेटअप

```csharp
    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>();
    }
```

You'll see I have a bunch of alternative optional parameters here allowing me to inject different options for different test types

### टेस्ट्स

तो अब मैं सभी इस सेटअप जगह पर है मैं अब के लिए परीक्षण लिखना शुरू कर सकता हूँ `UmamiClient` विधि

#### भेजें (S)

क्या यह सब सेटअप का मतलब है कि हमारे परीक्षण वास्तव में काफी सरल हो सकता है

```csharp
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` सिर्फ भेजे गए प्रतिक्रिया को प्रतिबिंबित करने के लिए और यह सुनिश्चित करता है कि वह वापस भेजता है क्या मैं आशा करता हूँ

```csharp
    [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

यह उपयोग करता है `HttpContextAccessor` पथ को सेट करने के लिए `/testpath` और फिर जाँच करता है कि `UmamiClient` यह सही रूप से भेजता है.

```csharp
    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;
    }

```

यह हमारे उमामी क्लाइंट कोड के लिए महत्वपूर्ण है क्योंकि प्रत्येक अनुरोध से भेजे गए डेटा का अधिकांश वास्तव में गतिशील रूप से उत्पन्न किया जाता है `HttpContext` वस्तु. तो हम एक में कुछ भी नहीं भेज सकते `await umamiClient.TrackPageView();` कॉल और यह अभी भी सही डेटा Url से बाहर निकाल कर भेजेगा `HttpContext`.

जैसा कि हम ''' बाद में देखेंगे यह''' भी महत्वपूर्ण है आश्चर्य के समान वस्तुओं को भेजने `UserAgent` और `IPAddress` चूंकि इन का उपयोग Umami सर्वर द्वारा डेटा और 'trackM SK1 उपयोगकर्ता दृश्य को बिना कुकीज़ के ट्रैक करने के लिए किया जाता है

इस पूर्वानुमानीय होने के लिए हम में एक समूह के कंस्ट परिभाषित करें `Consts` वर्ग. तो हम अनुमानित प्रतिक्रियाओं और अनुरोधों के विरुद्ध परीक्षण कर सकते हैं

```csharp
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 = "test@test.com";

    public const string UserId = "11224456";
    
    public const string UserName = "Test User";
    
    public const string SessionId = "B41A9964-FD33-4108-B6EC-9A6B68150763";
}
```

## और परीक्षण

हम अभी भी परीक्षण करने के लिए है Umami के लिए परीक्षण रणनीति का सिर्फ शुरू है `IHostedService` और वास्तविक डेटा के विरुद्ध परीक्षण Umami उत्पन्न करता है (जो कोई भी documented नहीं है, लेकिन कुछ उपयोगी डाटा के साथ एक JWT टोकन है

```json
{
  "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 के परीक्षण का प्रारंभ है। . नेट पैकेज।