मैं कई उत्तरों से आश्वस्त नहीं हूँ।
सबसे पहले, कल्पना करें कि आप एक विधि का परीक्षण करना चाहते हैं जो उपयोग करता है HttpClient
। आपको HttpClient
अपने कार्यान्वयन में सीधे तात्कालिक नहीं होना चाहिए । आपको अपने लिए एक उदाहरण प्रदान करने की जिम्मेदारी के साथ एक कारखाने को इंजेक्ट करना चाहिए HttpClient
। इस तरह आप बाद में उस कारखाने का मजाक उड़ा सकते हैं और जो HttpClient
चाहें वापस लौट सकते हैं (जैसे: एक नकली HttpClient
और असली नहीं)।
तो, आप निम्नलिखित की तरह एक कारखाना होगा:
public interface IHttpClientFactory
{
HttpClient Create();
}
और एक कार्यान्वयन:
public class HttpClientFactory
: IHttpClientFactory
{
public HttpClient Create()
{
var httpClient = new HttpClient();
return httpClient;
}
}
बेशक आपको इस कार्यान्वयन में अपने IoC कंटेनर में पंजीकरण करना होगा। यदि आप ऑटोफेक का उपयोग करते हैं तो यह कुछ इस तरह होगा:
builder
.RegisterType<IHttpClientFactory>()
.As<HttpClientFactory>()
.SingleInstance();
अब आपके पास एक उचित और परीक्षण योग्य कार्यान्वयन होगा। कल्पना करें कि आपका तरीका कुछ इस तरह है:
public class MyHttpClient
: IMyHttpClient
{
private readonly IHttpClientFactory _httpClientFactory;
public SalesOrderHttpClient(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<string> PostAsync(Uri uri, string content)
{
using (var client = _httpClientFactory.Create())
{
var clientAddress = uri.GetLeftPart(UriPartial.Authority);
client.BaseAddress = new Uri(clientAddress);
var content = new StringContent(content, Encoding.UTF8, "application/json");
var uriAbsolutePath = uri.AbsolutePath;
var response = await client.PostAsync(uriAbsolutePath, content);
var responseJson = response.Content.ReadAsStringAsync().Result;
return responseJson;
}
}
}
अब परीक्षण हिस्सा है। HttpClient
फैली हुई है HttpMessageHandler
, जो अमूर्त है। चलो एक "मॉक" बनाते हैं जो HttpMessageHandler
एक प्रतिनिधि को स्वीकार करता है ताकि जब हम मॉक का उपयोग करें तो हम प्रत्येक परीक्षण के लिए प्रत्येक व्यवहार को भी सेट कर सकें।
public class MockHttpMessageHandler
: HttpMessageHandler
{
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _sendAsyncFunc;
public MockHttpMessageHandler(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> sendAsyncFunc)
{
_sendAsyncFunc = sendAsyncFunc;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return await _sendAsyncFunc.Invoke(request, cancellationToken);
}
}
और अब, और Moq (और फ़्लुएंटसर्विज़न, एक पुस्तकालय जो इकाई परीक्षणों को और अधिक पठनीय बनाता है) की मदद से, हमारे पास इकाई विधि का उपयोग करने के लिए आवश्यक सब कुछ है जो हमारे पोस्टएज़्यूनिक का उपयोग करता है HttpClient
public static class PostAsyncTests
{
public class Given_A_Uri_And_A_JsonMessage_When_Posting_Async
: Given_WhenAsync_Then_Test
{
private SalesOrderHttpClient _sut;
private Uri _uri;
private string _content;
private string _expectedResult;
private string _result;
protected override void Given()
{
_uri = new Uri("http://test.com/api/resources");
_content = "{\"foo\": \"bar\"}";
_expectedResult = "{\"result\": \"ok\"}";
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
var messageHandlerMock =
new MockHttpMessageHandler((request, cancellation) =>
{
var responseMessage =
new HttpResponseMessage(HttpStatusCode.Created)
{
Content = new StringContent("{\"result\": \"ok\"}")
};
var result = Task.FromResult(responseMessage);
return result;
});
var httpClient = new HttpClient(messageHandlerMock);
httpClientFactoryMock
.Setup(x => x.Create())
.Returns(httpClient);
var httpClientFactory = httpClientFactoryMock.Object;
_sut = new SalesOrderHttpClient(httpClientFactory);
}
protected override async Task WhenAsync()
{
_result = await _sut.PostAsync(_uri, _content);
}
[Fact]
public void Then_It_Should_Return_A_Valid_JsonMessage()
{
_result.Should().BeEquivalentTo(_expectedResult);
}
}
}
जाहिर है यह परीक्षण मूर्खतापूर्ण है, और हम वास्तव में हमारे नकली का परीक्षण कर रहे हैं। लेकिन आप विचार समझ गये। आपको अपने कार्यान्वयन के आधार पर सार्थक तर्क का परीक्षण करना चाहिए जैसे कि ।।
- यदि प्रतिक्रिया की कोड स्थिति 201 नहीं है, तो क्या इसे अपवाद फेंकना चाहिए?
- यदि प्रतिक्रिया पाठ को पार्स नहीं किया जा सकता है, तो क्या होना चाहिए?
- आदि।
इस उत्तर का उद्देश्य कुछ ऐसा परीक्षण करना था जो HttpClient का उपयोग करता है और ऐसा करने के लिए यह एक अच्छा साफ तरीका है।
HttpClient
अपने इंटरफ़ेस में ए एक्सपोज़ करना जहाँ समस्या है। आप अपने ग्राहक कोHttpClient
ठोस वर्ग का उपयोग करने के लिए मजबूर कर रहे हैं । इसके बजाय, आप एक को बेनकाब करना चाहिए अमूर्त कीHttpClient
।