# बिना परेशानी के इकाई जाँच  दिल की जाँच करता है

<datetime class="hidden">2025-11-29T07:00</datetime>

<!--category-- xUnit, Unit Testing, HttpClient -->
## परिचय

जाँच कोड जो उपयोग में लेते हैं `HttpClient`, पारंपरिक दृष्टिकोण में ठट्ठा करना शामिल है `HttpMessageHandler` यह काम करता है के रूप में फ्रेमवर्क उपयोग कर रहा है. जब तक यह काम करता है, यह Roquck, समारोह, और स्पष्ट रूप से एक बिट बदसूरत हो सकता है. वहाँ एक शुद्ध विकल्प है: इस्तेमाल किया जा रहा है. `DelegatingHandler` जांच हैंडलर बनाने के लिए जो वास्तविक HTTP अंत- बिन्दुओं की तरह व्यवहार करता है.

इस पोस्ट में मैं तुम्हें दिखाता हूँ क्यों आप ठट्ठाों को पूरी तरह छोड़ सकते हैं और इस्तेमाल कर सकते हैं `DelegatingHandler` अधिक पढ़ने योग्य, बनाए रखने योग्य, तथा पक्का परीक्षण कोड के लिए.

[TOC]

## नकली संदेशर के साथ समस्या

यहाँ क्या आम बात है `HttpMessageHandler` हंसी ठट्ठा कर रहे हैं जैसे मोजे के साथ:

```csharp
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) =>
    {
        var requestBody = request.Content?.ReadAsStringAsync(cancellationToken).Result;
        return new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent(requestBody ?? "No content", Encoding.UTF8, "application/json")
        };
    });

var client = new HttpClient(mockHandler.Object);
```

इसमें कई मुद्दों पर चर्चा की गयी है:

1. **के- लिंक- स्टेटस** - क्या सरल व्यवहार किया जाना चाहिए के लिए पकाना चाहिए के मेहमान
2. **सुरक्षित विधि समारोह** - आप की जरूरत है `Protected()` और `ItExpr` क्योंकि `SendAsync` संरक्षित है
3. **पढ़ने के लिए कठिन** - वास्तविक जांच तर्क सेटअप समारोह में दफन है
4. **री- नहीं** - हर जाँच को समान सेटअप कोड की जरूरत है
5. **ब्रिटल** - स्ट्रिंग आधारित विधि नाम गलत पाने के लिए आसान है

## काम करनेवाले वैकल्पिक

`DelegatingHandler` इस उद्देश्य के लिए बनाया गया एक निर्माण वर्ग है - वास्तव में इस उद्देश्य के लिए बनाया गया एचटीटीपी निवेदन वे नेटवर्क हिट से पहले. यह क्या मध्य हॉलिंग हैंडलर, लॉगिंग हैंडलर, और प्रमाणीकरण हैंडलर उत्पादन में प्रयोग करते हैं.

यहाँ एक ही कार्यशील कार्य है प्रयोग किया जा रहा है `DelegatingHandler`:

```csharp
public class EchoHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        var content = request.Content != null
            ? await request.Content.ReadAsStringAsync(cancellationToken)
            : "No content";

        return new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent(content, Encoding.UTF8, "application/json")
        };
    }
}
```

इसे प्रयोग किया जा रहा है:

```csharp
var client = new HttpClient(new EchoHandler());
```

यही कारण है कि यह है. कोई उपहास फ्रेमवर्क, कोई संरक्षित विधि नहीं, कोई वाक्यांश आधारित विधि नाम.

## एक वास्तविक विश्‍व उदाहरण: अनुवाद सेवा हैंडलर

यहाँ एक अनुवाद सेवा जाँच हैंडलर से एक अधिक जटिल उदाहरण है:

```csharp
public class TranslateDelegatingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        var absPath = request.RequestUri?.AbsolutePath;
        var method = request.Method;

        return absPath switch
        {
            "/translate" when method == HttpMethod.Post => await HandleTranslate(request),
            "/translate" => new HttpResponseMessage(HttpStatusCode.OK),
            "/health" => new HttpResponseMessage(HttpStatusCode.OK),
            _ => new HttpResponseMessage(HttpStatusCode.NotFound)
        };
    }

    private static async Task<HttpResponseMessage> HandleTranslate(HttpRequestMessage request)
    {
        var content = await request.Content!.ReadFromJsonAsync<TranslateRequest>();

        // Simulate error for specific test case
        if (content?.TargetLanguage == "xx")
            return new HttpResponseMessage(HttpStatusCode.InternalServerError);

        var response = new TranslateResponse("es", new[] { "Texto traducido" });
        return new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = JsonContent.Create(response)
        };
    }
}
```

यह हैंडलर:

- भिन्न व्यवहारों के लिए भिन्न पथ रूट करता है
- फैसले लेने के लिए हवाई जहाज़ से जो गुज़ारिश की जाती है
- विशिष्ट घटना के लिए उचित त्रुटि कोड बताता है
- पूरी तरह पढ़ने लायक है तथा स्वयं को नियंत्रित कर रहा है

## डिपेंडेंसी के साथ सेटअप किया जा रहा है

कब प्रयोग किया जा रहा है `IHttpClientFactory` (जिसे आप होना चाहिए), जांच हैंडलर सीधा है:

```csharp
public static IServiceCollection SetupTestServices(DelegatingHandler handler)
{
    var services = new ServiceCollection();

    services.AddHttpClient<ITranslationService, TranslationService>(client =>
    {
        client.BaseAddress = new Uri("https://test.local");
    })
    .ConfigurePrimaryHttpMessageHandler(() => handler);

    return services;
}
```

फिर अपनी जाँच में:

```csharp
[Fact]
public async Task Translate_ReturnsTranslatedText()
{
    var services = SetupTestServices(new TranslateDelegatingHandler());
    var provider = services.BuildServiceProvider();
    var service = provider.GetRequiredService<ITranslationService>();

    var result = await service.TranslateAsync("Hello", "es");

    Assert.Equal("Texto traducido", result);
}

[Fact]
public async Task Translate_InvalidLanguage_ThrowsException()
{
    var services = SetupTestServices(new TranslateDelegatingHandler());
    var provider = services.BuildServiceProvider();
    var service = provider.GetRequiredService<ITranslationService>();

    await Assert.ThrowsAsync<HttpRequestException>(
        () => service.TranslateAsync("Hello", "xx"));
}
```

## विस्तृत पैटर्न: विन्यासयोग्य हैंडलर्स

अधिक रिसर्च के लिए, आप हैंडलर बना सकते हैं जो कॉन्फ़िगरेशन स्वीकार करता है:

```csharp
public class ConfigurableHandler : DelegatingHandler
{
    private readonly Dictionary<string, Func<HttpRequestMessage, Task<HttpResponseMessage>>> _routes;

    public ConfigurableHandler()
    {
        _routes = new Dictionary<string, Func<HttpRequestMessage, Task<HttpResponseMessage>>>();
    }

    public ConfigurableHandler WithRoute(string path, HttpStatusCode status)
    {
        _routes[path] = _ => Task.FromResult(new HttpResponseMessage(status));
        return this;
    }

    public ConfigurableHandler WithRoute(string path, object responseBody)
    {
        _routes[path] = _ => Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = JsonContent.Create(responseBody)
        });
        return this;
    }

    public ConfigurableHandler WithRoute(
        string path,
        Func<HttpRequestMessage, Task<HttpResponseMessage>> handler)
    {
        _routes[path] = handler;
        return this;
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        var path = request.RequestUri?.AbsolutePath ?? "";

        if (_routes.TryGetValue(path, out var handler))
            return await handler(request);

        return new HttpResponseMessage(HttpStatusCode.NotFound);
    }
}
```

उपयोग:

```csharp
var handler = new ConfigurableHandler()
    .WithRoute("/api/users", new[] { new User("Alice"), new User("Bob") })
    .WithRoute("/api/health", HttpStatusCode.OK)
    .WithRoute("/api/error", HttpStatusCode.InternalServerError);

var client = new HttpClient(handler);
```

## क्यों छल - कपट से काम करनेवाले को धोखा देने के लिए चुनें?

STAGTATMEMM- आधारित हँसी-मज़ाकिंग
|--------|-------------------|-------------------|
| **कोड की पंक्तियाँ** दुख की बात है कि कम - से - कम लोगों की मौत हो जाती है
| **पढ़ने की क्षमता** INRIN कम (अनुल भारी) बहुतेरे उच्च (सिर्फ C#) D गुनाहों की वजह से
| **रीस्टमेंटमेंटमेंटमेंट्सGenericName** ख़ोनाड एनईसी एनईएस बढ़िया
| **डिबगिंग** हार्डर (mock जादू) Carnffors (के माध्यम से)
| **रीफ्रेक्टरिंग** स्ट्रेन्टेन्ट रॉबसन
| **वक्र को समझ रहा है** INBS Steut (Moqaqs) japan. kgm
| **डिपेंडेंसीज़** CSV की आवश्यकता है मोजेई कुछ नहीं (अंतर्निहित)

## जब नकल करने से अब भी होश उड़ जाता है

उचित होने के लिए, ऐसे दृश्‍य होते हैं जहाँ मोफ़िक उपहास अब भी उचित हो सकता है:

1. **एक सरल प्रतिक्रिया** - अगर आपको एक बार एक एकल-रिशन हैंडलर की जरूरत है, इनलाइन मोजे जल्दी हो सकता है
2. **गंतव्य खोलें** - मोक है `Verify()` कॉल का दावा करने के लिए उपयोगी है
3. **मौज़ूदा कोड बेस** - अगर आपकी टीम पहले से ही विस्तृत मोफाउंड है

सत्यापन के लिए, आप इसे भी विनाशकारी करने के लिए जोड़ सकते हैं:

```csharp
public class VerifyingHandler : DelegatingHandler
{
    public List<HttpRequestMessage> ReceivedRequests { get; } = new();

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        ReceivedRequests.Add(request);
        return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
    }
}
```

## कंटेनमेंट

उपयोग में `DelegatingHandler` दिल की जाँच के लिए आपको देता है:

- **कॉम्पैक्ट कोड** - कोई हँसी कार्यक्रम नहीं
- **पढ़ने योग्य जाँच** - सिर्फ नियमित C# क्लास
- **रीक्लासेबल हैंडलर** - जाँच वर्गों में साझा करें
- **आसान डिबगिंग** - ब्रेकपाइंट सेट करें, चरण कोड के माध्यम से
- **शून्य डिपेंडेंसीज़** - यह .नेट में बनाया गया है

अगली बार जब आप इसके लिए पहुँच जाते हैं `Mock<HttpMessageHandler>`, ज़रा गौर कीजिए कि एक साधारण व्यक्‍ति क्या करता है `DelegatingHandler` आपके भविष्य में स्वयं (और आपके टीम ऐक्सिस), सफाई के लिए आपका धन्यवाद करेंगे, और अधिक योग्य जाँच कोड को बनाए रखिए ।

इस समस्या में जाँच परियोजनाओं को देखें इस रूप में कार्य में इस उदाहरण के लिए।