2012-05-21 20 views
25

स्टबिंग या मॉकिंग मैं प्रोजेक्ट में नई वेब एपीआई बिट्स का उपयोग कर रहा हूं, और मुझे पता चला है कि मैं सामान्य HttpMessageRequest का उपयोग नहीं कर सकता, क्योंकि मुझे अनुरोध में क्लाइंट प्रमाणपत्र जोड़ना होगा। नतीजतन, मैं HttpClient का उपयोग कर रहा हूं (इसलिए मैं WebRequestHandler का उपयोग कर सकता हूं)। यह सब अच्छी तरह से काम करता है, सिवाय इसके कि यह कम से कम राइनो मोक्स के लिए अनुकूल/मॉक अनुकूल नहीं है।एएसपी.नेट वेब एपीआई एचटीपी क्लाइंट

मैं आमतौर पर HttpClient के आसपास एक रैपर सेवा बनाउंगा जो मैं इसके बजाय उपयोग करूंगा, लेकिन यदि संभव हो तो मैं इसे टालना चाहूंगा, क्योंकि मुझे कई तरीकों से लपेटने की आवश्यकता होगी। मुझे आशा है कि को कैसे दबाएं इस बारे में कोई सुझाव है कि मुझे — कुछ याद आ रही है?

उत्तर

11

मैं Moq का उपयोग करता हूं और मैं HttpClient को बाहर निकाल सकता हूं। मुझे लगता है कि राइनो मॉक के लिए यह वही है (मैंने खुद से कोशिश नहीं की है)। नीचे कोड काम करना चाहिए तुम सिर्फ ठूंठ HttpClient चाहते हैं:

var stubHttpClient = new Mock<HttpClient>(); 
ValuesController controller = new ValuesController(stubHttpClient.Object); 

कृपया मुझे ठीक कर लें मैं गलत हूँ। मुझे लगता है कि आप यहां उल्लेख कर रहे हैं कि एचटीपी क्लाइंट के भीतर सदस्यों को बाहर निकालना।

सबसे लोकप्रिय अलगाव/नकली वस्तु चौखटे आप ठूंठ गैर आभासी सदस्यों उदाहरण के लिए नीचे दिए गए कोड एक अपवाद

stubHttpClient.Setup(x => x.BaseAddress).Returns(new Uri("some_uri"); 

तुम भी उल्लेख किया है कि आप से बचने के लिए चाहते हैं फेंकता पर/सेटअप अनुमति नहीं दी जाएगी एक रैपर बनाना क्योंकि आप बहुत सारे HttpClient सदस्यों को लपेटेंगे। स्पष्ट नहीं है कि आपको कई तरीकों को लपेटने की आवश्यकता क्यों है, लेकिन आप केवल उन्हीं विधियों को आसानी से लपेट सकते हैं जिन्हें आप चाहते हैं।

उदाहरण के लिए:

public interface IHttpClientWrapper { Uri BaseAddress { get; }  } 

public class HttpClientWrapper : IHttpClientWrapper 
{ 
    readonly HttpClient client; 

    public HttpClientWrapper() { 
     client = new HttpClient(); 
    } 

    public Uri BaseAddress { 
     get 
     { 
      return client.BaseAddress; 
     } 
    } 
} 

अन्य विकल्प मैं तुम्हें (वहाँ तो मैं कोड नहीं लिखेंगे उदाहरण के बहुत सारे) माइक्रोसॉफ्ट मोल्स फ्रेमवर्क http://research.microsoft.com/en-us/projects/moles/ माइक्रोसॉफ्ट नकली के लिए लाभ हो सकता है लगता है कि: (यदि आप VS2012 परम) http://msdn.microsoft.com/en-us/library/hh549175.aspx

+1

उत्तर के लिए धन्यवाद। मैं रैपर दृष्टिकोण के साथ जा रहा समाप्त हो गया। अगर मुझे इसे फिर से करना पड़ा, तो शायद मैं टाइपमैक, या एमएस समाधानों में से एक का उपयोग करता हूं। –

+0

मैंने शुरुआत में एक सीलबंद वर्ग के भीतर एक विशिष्ट चीज़ के लिए अपना कंक्रीट कार्यान्वयन लिखा था और अंदर कसकर जोड़ दिया था .. लेकिन मुझे अब पता चला है कि 'मोक' के साथ अच्छी तरह से काम करने के परीक्षणों को प्राप्त करने के लिए मुझे लगता है कि मुझे कक्षा के कुछ हिस्सों को बेहतर परीक्षण प्राप्त करने के लिए अवश्य करना चाहिए कवरेज। मुझे पता था कि मुझे ऐसा करना था, मुझे बस इसकी तलाश करनी पड़ी, और फिर अपने आप को आलसी न होने का विश्वास दिलाएं: डी – ppumkin

59

उपयोग कर रहे हैं उत्कृष्ट विचारों को पहले से ही @Raj द्वारा प्रस्तुत करने के लिए एक विकल्प के रूप में, यह एक कदम कम जाना संभव हो सकता है और नकली उपहास करने के लिए/इसके बजाय।

यदि आप किसी भी वर्ग की जरूरत है कि एक HttpClient निर्माता में एक निर्भरता इंजेक्शन पैरामीटर के रूप में यह स्वीकार करते हैं, तो जब इकाई परीक्षण आप एक HttpClient कि अपनी खुद की HttpMessageHandler इंजेक्शन दिया गया है में पारित कर सकते हैं बनाते हैं। इस प्रकार यह सरल वर्ग, केवल एक ही सार विधि है कि आप लागू करने की आवश्यकता है:

public class FakeHttpMessageHandler : HttpMessageHandler 
    { 
    public HttpRequestMessage RequestMessage { get; private set; } 

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

मेरे तुच्छ उदाहरण सिर्फ बाद में निरीक्षण के लिए एक सार्वजनिक संपत्ति में HttpRequestMessage बचत होती है और HTTP 200 (ठीक) देता है, लेकिन आप एक कन्स्ट्रक्टर जोड़कर इसे बढ़ा सकता है जो परिणाम को सेट करता है जिसे आप वापस करना चाहते हैं।

आप इस तरह इस वर्ग का उपयोग करेंगे:

public void foo() 
    { 
    //Arrange 
    var fakeHandler = new FakeHttpMessageHandler(); 
    var client = new HttpClient(fakeHandler); 
    var SUT = new ClassUnderTest(client); 

    //Act 
    SUT.DomSomething(); 

    //Assert 
    fakeHandler.RequestMessage.Method.ShouldEqual(HttpMethod.Get); // etc... 
    } 

इस दृष्टिकोण के लिए सीमाओं के लिए एक विधि है कि एक से अधिक अनुरोध करता है या एक से अधिक HttpClient रों बनाने के लिए की जरूरत है, उदाहरण के लिए, तो नकली हैंडलर शुरू हो सकता है कर रहे हैं, बहुत जटिल बनने के लिए।हालांकि, यह साधारण मामलों के लिए विचार लायक हो सकता है।

+1

हालांकि यह एक साफ विचार है, यह दृष्टिकोण बहुत भंगुर परीक्षण तैयार करेगा। HttpClient कार्यान्वयन भविष्य में बदल सकता है। और आप परीक्षा कक्षा के आंतरिक कार्यों पर निर्भर करते हैं। रैपर आईएमएचओ अभी भी सबसे अच्छा तरीका है। –

+6

यह एक सार्वजनिक कन्स्ट्रक्टर पैरामीटर है। मुझे नहीं लगता कि यह बदलने जा रहा है। मुझे यह जवाब बहुत पसंद है। – Kugel

+1

शानदार, उत्तर स्वीकार किया जाना चाहिए। मैं @ कुगेल से सहमत हूं - इसमें बदलाव होने की संभावना नहीं है और यह एक जोखिम है जिसे मैं लेने के इच्छुक हूं। –

34

मैंने कुछ महीने पहले लाइब्रेरी जारी की जिसे MockHttp कहा जाता है जो उपयोगी हो सकता है। यह एक धाराप्रवाह (और एक्स्टेंसिबल) एपीआई के साथ एक कस्टम HttpMessageHandler का उपयोग करता है। आप अपनी सेवा कक्षा में मॉक किए गए हैंडलर (या HttpClient) को इंजेक्ट कर सकते हैं और यह कॉन्फ़िगर किए जाने पर प्रतिक्रिया देगा।

नीचे मूल उपयोग दिखाता है। When और Respond विधियों में ओवरलोड लोड का एक गुच्छा है, जिसमें कस्टम लॉजिक चल रहा है। documentation on the GitHub page बहुत अधिक जानकारी में चला जाता है।

var mockHttp = new MockHttpMessageHandler(); 

// Setup a respond for the user api (including a wildcard in the URL) 
mockHttp.When("http://localhost/api/user/*") 
     .Respond("application/json", "{'name' : 'Test McGee'}"); // Respond with JSON 

// Inject the handler or client into your application code 
var client = new HttpClient(mockHttp); 

var response = async client.GetAsync("http://localhost/api/user/1234"); 
// or without async: var response = client.GetAsync(...).Result; 

var json = await response.Content.ReadAsStringAsync(); 

// No network connection required 
Console.Write(json); // {'name' : 'Test McGee'} 
+0

वास्तव में इस पुस्तकालय की तरह, और $ httpBackend के समानताएं। मैं इस दृष्टिकोण से चला गया हूं और यह अच्छी तरह से काम कर रहा है। –

+0

धन्यवाद जेम्स, आपको यह पसंद है! –

+0

हम स्पष्ट रूप से उसी लाइन के साथ सोच रहे थे।मेरा उपयोग मामला बहुत आसान था और अब तक यह उचित नहीं होगा, लेकिन मुझे लगता है कि अगर आप इस क्षेत्र में बहुत सारे काम कर रहे हैं तो ऐसी लाइब्रेरी एक वास्तविक समय बचत होगी। मैं अगली बार परियोजना को बुकमार्क करने जा रहा हूं मुझे इस तरह कुछ चाहिए। –

संबंधित मुद्दे