Moles MS Research का एक हल्का उपकरण है, जो स्वचालित रूप से इंटरफेस और आभासी तरीकों के लिए स्टब्स उत्पन्न कर सकता है, साथ ही सीलबंद कक्षाएं, गैर-आभासी और स्थिर तरीकों (!) के लिए, कोड उत्पन्न करके जो बाद में वांछित प्रतिनिधि में फिसल सकता है, एक विशिष्ट विधि के बजाय कहा जाता है! । पहले प्रकार के स्टब को स्टब्स कहा जाता है, और दूसरा मोल्स है। मैंने अतुल्यकालिक संचालन का परीक्षण करने के लिए इस चीज़ का उपयोग किया, जो मैंने
पहले के बारे में बात की थी , लेकिन चलो क्रम में सब कुछ के बारे में
बात करते हैं।
स्टब्स
आइए ऐसे एक उदाहरण को देखें। मान लीजिए कि हम यूनिट परीक्षणों के मूल्य, साथ ही साथ डिपेंडेंसी इनवर्सन, और अन्य पागलपनपूर्ण सिद्धांतों और पैटर्न (शायद सभी अन्य
ठोस सिद्धांत, और शायद यहां तक कि
FIRST ) जैसे सिद्धांतों को समझते हैं। और यह भी नहीं है कि हम परीक्षण या अंकल बॉब के प्रशंसक हैं, बल्कि केवल इसलिए कि हम जानते हैं कि उच्च कनेक्टिविटी खराब है। इसलिए, हम इंटरफेस को आवंटित करके और फिर उन्हें क्लास कंस्ट्रक्टर या विधियों में इंजेक्ट करके निर्भरता कम करने की कोशिश करते हैं, जिन्हें इन कार्यों को करने के लिए इन इंटरफेस की आवश्यकता होती है।
तो, मान लेते हैं कि हमारे कोड में कुछ अमूर्तता के लिए, हमने
IFoo इंटरफ़ेस आवंटित किया है और कुछ वर्ग बनाया है जो इस इंटरफ़ेस का उपयोग करता है।
namespace PlayingWithMoles
{
// , -
public interface IFoo
{
string SomeMethod();
}
// - , IFoo
public class FooConsumer
{
// ""
public FooConsumer(IFoo foo)
{
this .foo = foo;
}
// , - IFoo
public void DoStuff()
{
var someResults = foo.SomeMethod();
Console .WriteLine( "Doing stuff. IFoo.SomeMethod results: {0}" , someResults);
}
private readonly IFoo foo;
}
}
* This source code was highlighted with Source Code Highlighter .
अब, मान लें कि हमारे उज्ज्वल दिमागों को कम उज्ज्वल विचार से दौरा किया गया था, और क्या समान
FooConsumer वर्ग का एक इकाई परीक्षण लिखना है, समान रूप से अद्भुत
DoStuff विधि के साथ (यह स्पष्ट है कि इस तरह के कोड का परीक्षण करने का अर्थ लगभग शून्य है, लेकिन आपने विचार को समझा) । इसलिए,
FooConsumer वर्ग का एक उदाहरण बनाने के लिए,
आपको IFoo इंटरफ़ेस का कार्यान्वयन ढूंढना होगा, जो हमारे कोड में हो सकता है, लेकिन इस तथ्य के बारे में नहीं कि यह यूनिट परीक्षणों के लिए उपयुक्त है, क्योंकि हमारे लिए इसका उपयोग करना मुश्किल (या असंभव) हो सकता है, क्योंकि यह वर्ग निर्भर हो सकता है। एक और वर्ग, जो तीसरे और इतने पर निर्भर करता है। बेशक, हमारे भाई की ऐसी चाल नहीं चल सकती है, और अगर हमने परीक्षण किया, तो हम निश्चित रूप से इस मामले को समाप्त कर देंगे। इसलिए, हम इसे लेते हैं और इंटरफ़ेस को हाथ से लागू करते हैं, क्योंकि केवल एक ही तरीका है और यह किसी भी कठिनाइयों का कारण नहीं बनता है, जिसके परिणामस्वरूप हमें निम्नलिखित प्रकार का परीक्षण मिलता है:
[TestClass()]
public class FooConsumerTest
{
class FooTester : IFoo
{
public string SomeMethod()
{
return "Test string" ;
}
}
[TestMethod]
public void DoStuffTest()
{
IFoo foo = new FooTester();
FooConsumer target = new FooConsumer(foo);
target.DoStuff();
}
}
* This source code was highlighted with Source Code Highlighter .
अब आप इस कोड को चला सकते हैं और आउटपुट विंडो में देख सकते हैं:
सामान करना। IFoo.SomeMethod परिणाम: हैलो, कस्टम स्टब । हां, यह मुश्किल नहीं था, लेकिन आप और मैं जानते हैं कि वास्तविक अनुप्रयोगों की समस्याएं विवरण में निहित हैं और व्यवहार में हमें इससे कहीं अधिक जटिल इंटरफेस का सामना करना पड़ता है और हमारे हाथों से प्रत्येक इंटरफ़ेस का कार्यान्वयन शायद ही सबसे दिलचस्प कहा जा सकता है काम की दुनिया में।
तो, मोल्स लाइब्रेरी। इस उपकरण के साथ स्टब्स बनाना निम्नानुसार है। परीक्षणों के साथ एक परियोजना में, व्यापार तर्क के साथ विधानसभा पर राइट-क्लिक करें जिसे आप परीक्षण करना चाहते हैं और "विधानसभा में मोल जोड़ें" का चयन करें, जिसके बाद परियोजना में "MyAssemblyName.moles" फ़ाइल को जोड़ा जाएगा, और इस परियोजना को तैयार करने के बाद कनेक्टेड असेंबली की सूची असेंबली MyAssemblyName.Moles को प्रदर्शित करेगी, जिसमें सभी उत्पन्न स्टब्स होंगे। यह उपकरण तब व्यापार तर्क के साथ सफल बिल्ड बिल्ड को स्वचालित रूप से ट्रैक करेगा और स्वचालित रूप से स्टब्स को पुन: उत्पन्न करेगा। MyAssemblyName.moles फ़ाइल एक विशिष्ट प्रारूप में एक सरल xml फ़ाइल है, जो असेंबली का नाम सेट करती है जिसके लिए स्टब्स उत्पन्न होंगे, साथ ही उनकी पीढ़ी के लिए कुछ पैरामीटर (उदाहरण के लिए, आप निर्दिष्ट कर सकते हैं कि आप किस प्रकार के स्टब्स, स्टब्स या स्टब्स के प्रकार उत्पन्न करना चाहते हैं। मोल्स) और अधिक)।
नोट
संस्करण 0.94 से शुरू होकर, मोल्स फ़ाइल योजना बदल गई है। इससे पहले, आप स्टब्स के स्वचालित संकलन को रद्द कर सकते थे, कॉन्फ़िगरेशन फ़ाइल के किसी एक भाग में संकलन = गलत सेट कर सकते थे, जिसके कारण यह तथ्य सामने आया था कि स्टब्स के साथ असेंबली उत्पन्न नहीं हुई थी, और इसके बजाय उत्पन्न फ़ाइल को वर्तमान प्रोजेक्ट में सीधे जोड़ा गया था। 0.94 संस्करण के साथ शुरू, यह संभावना गायब हो गई है, लेकिन आप अभी भी देख सकते हैं कि उत्पन्न कोड कैसा दिखता है, आपके प्रोजेक्ट के सबफ़ोल्डर में अफवाह है। इसलिए, उदाहरण के लिए, इस उपकरण का वर्तमान संस्करण उत्पन्न फ़ाइलों को निम्न स्थान पर सहेजता है: MyTestProject \ obj \ Debug \ Moles \ sl \ mgsl।आइए इस टूल द्वारा हमारे लिए बनाए गए कोड के सरलीकृत संस्करण को देखें:
namespace PlayingWithMoles.Moles
{
public class SIFoo
: Microsoft.Moles.Framework.Stubs.StubBase
, IFoo
{
string IFoo.SomeMethod()
{
var sh = this .SomeMethod;
if (sh != null )
return sh.Invoke();
else
{
// Behavior-,
}
}
// Sets the stub of IFoo.SomeMethod
public Func< string > SomeMethod;
}
}
* This source code was highlighted with Source Code Highlighter .
तो, उत्पन्न वर्ग स्पष्ट रूप से मूल इंटरफ़ेस को लागू करता है और इसमें प्रतिनिधि होते हैं जिनके प्रकार संबंधित विधियों के हस्ताक्षर के अनुरूप होते हैं। चूँकि हमारी पद्धति किसी भी पैरामीटर और रिटर्न
स्ट्रिंग को स्वीकार नहीं करती
है , स्टब में
फंक <string> (यानी, एक प्रतिनिधि जो
स्ट्रिंग लौटाता है और कोई भी पैरामीटर स्वीकार नहीं करता है) का एक प्रतिनिधि होता है। इसके अलावा,
SomeMethod पद्धति में, इस प्रतिनिधि को बस कहा जाता है (यदि यह प्रतिनिधि
अशक्त है , तो एक
StubNotImplementedException डिफ़ॉल्ट रूप से डाली जाएगी, लेकिन इस व्यवहार को बदला जा सकता है)। ध्यान दें कि स्टब क्लास का नाम है:
S InterfaceOrClassName, और यह
ओरिजिनल नेमस्पेस में है ।
मोल्स नेमस्पेस ।
अब अपने मूल परीक्षण को बदलते हैं और हमारे लिए उत्पन्न स्टब का उपयोग करते हैं:
[TestMethod]
public void DoStuffTestWithStubs()
{
var fooStub = new PlayingWithMoles.Moles.SIFoo();
fooStub.SomeMethod = () => "Hello, Stub!" ;
var target = new FooConsumer(fooStub);
target.DoStuff();
}
* This source code was highlighted with Source Code Highlighter .
इसे चलाने पर, हम, जैसा कि अपेक्षित है, निम्न पंक्ति देखेंगे:
सामान करना। IFoo.SomeMethod परिणाम: नमस्ते, मोल्स स्टब!मैं आपको एक बार फिर याद दिलाता हूं कि स्टब्स केवल इंटर-सील और गैर-सीलबंद कक्षाओं के वर्चुअल (सील नहीं) तरीकों के लिए उत्पन्न होते हैं। और कोई जादू नहीं है, क्योंकि इसके लिए, वारिस कक्षाएं या कक्षाएं जो आपके इंटरफेस को लागू करती हैं, उत्पन्न होती हैं, और कॉल शेड्यूलिंग अच्छे पुराने वर्चुअल कॉल के कारण होता है। हां, यह बात बहुत दिलचस्प है और आपको थोड़ा समय बचाने की अनुमति देता है, लेकिन इसमें कुछ भी आश्चर्यजनक नहीं है, इसके विपरीत ... मोल्स।
मोल्स
मोल्स दूसरे प्रकार के स्टब हैं, जो स्टब्स के समान उद्देश्यों के लिए डिज़ाइन किए गए हैं, लेकिन यह स्टैटिक या इंस्टेंस और गैर-वर्चुअल तरीकों से काम कर सकता है। मान
लेते हैं कि हमारा
FooConsumer वर्ग
IFoo इंटरफ़ेस से बंधा हुआ नहीं है, लेकिन एक विशिष्ट
Foo वर्ग के लिए जिसमें वर्चुअल तरीके शामिल नहीं हैं:
namespace PlayingWithMoles
{
// Foo,
// , IFoo
public class Foo
{
public string SomeMethod()
{
return "Hello, from non-virtual method." ;
}
}
// - , Foo
public class FooConsumer
{
// Foo
public FooConsumer(Foo foo)
{
this .foo = foo;
}
// , - Foo
public void DoStuff()
{
var someResults = foo.SomeMethod();
Console .WriteLine( "Doing stuff. Foo.SomeMethod results: {0}" ,
someResults);
}
private readonly Foo foo;
}
}
* This source code was highlighted with Source Code Highlighter .
यह स्पष्ट है कि अगर हमारे पास इस कोड को फिर से
भरने और
IFoo इंटरफ़ेस का चयन करने का अवसर है, तो यह इसके लायक है, लेकिन कभी-कभी यह व्यावहारिक नहीं हो सकता है, और कभी-कभी यह बिल्कुल भी असंभव है। अक्सर ऐसा होता है कि हमें किसी और का कोड मिलता है, निर्भरता का एक गुच्छा दिलाने के लिए जिसमें हमें धीरे-धीरे करने की आवश्यकता होती है, लेकिन हमें अब परीक्षण की आवश्यकता है; और यह असामान्य नहीं है जब यह कोड बदलना असंभव है, क्योंकि आप इसे नियंत्रित नहीं करते हैं; आखिरकार, यह अच्छी तरह से एक तृतीय-पक्ष पुस्तकालय या बाहरी संसाधनों तक पहुंच हो सकती है, जिसकी उपलब्धता परीक्षण आपका इरादा नहीं है।
यह वह जगह है जहां दूसरे प्रकार के प्लग इस उपकरण द्वारा उत्पन्न किए जा सकते हैं - मोल्स - मदद करेंगे। मोल्स एक समान तरीके से उत्पन्न होते हैं और एक ही नेस्टेड नेमस्पेस (ओरिजिनल
नेमस्पेस )।
मोल्स में स्थित होते हैं, हालांकि इनमें उपसर्ग
S के बजाय उपसर्ग
M होते हैं, हालांकि, वर्चुअल तरीकों और इंटरफेस के बजाय, हम गैर-वर्चुअल स्टेटिक तरीकों के व्यवहार को निर्दिष्ट कर सकते हैं। इस व्यवहार को कार्यान्वित करने के लिए, मोल्स लाइब्रेरी विशेष रूप से CLR Profiler का उपयोग करता है, यह कॉलबैक
ICorProfilerCallback :: JITCompilationStarted के कार्य को संसाधित करता है
, जिसमें हमारा प्रतिनिधि मूल विधि के बजाय "धक्का" देता है। नतीजतन, मूल विधि को कॉल करते समय, हमारे द्वारा प्रदान किए गए कोड के टुकड़े को बुलाया जाएगा।
इस प्रकार, हमारे मामले में, क्लास प्लेविथमॉल्स उत्पन्न होंगे।
Moles.M फू, और आइए देखें कि आप
FooConsumer वर्ग के नए संस्करण के अच्छे पुराने (और सबसे महत्वपूर्ण रूप से उपयोगी)
DoStuff विधि का परीक्षण कैसे कर सकते हैं:
[TestMethod]
[HostType( "Moles" )]
public void DoStuffTestWithMoles()
{
var fooMole = new PlayingWithMoles.Moles.MFoo();
fooMole.SomeMethod = () => "Hello, Mole!" ;
var target = new FooConsumer(fooMole);
target.DoStuff();
}
* This source code was highlighted with Source Code Highlighter .
[HostType ("Moles")] विशेषता पर ध्यान दें, जिसके बिना मोल्स का सारा जादू काम करना बंद कर देगा, क्योंकि, जैसा कि ऊपर उल्लेख किया गया है, वे कोड और CLR प्रोफाइलर के "इंस्ट्रूमेंटेशन" का उपयोग करते हैं। यह परीक्षण पिछले एक की तुलना में अधिक जटिल नहीं है, जिसमें स्टब्स का उपयोग किया गया था, और लॉन्च होने पर हमें बिल्कुल वही परिणाम मिलता है जिसकी हम उम्मीद करते हैं:
सामान। IFoo.SomeMethod परिणाम: नमस्ते, तिल!अब आइए एक और दिलचस्प उदाहरण देखें।
पिछली कई पोस्टों में, मैंने एसिंक्रोनस ऑपरेशंस के आस-पास टैम्बॉरीन के साथ डांस करने के विभिन्न तरीकों को देखा और उदाहरण के लिए मैंने वेब पेज कंटेंट के एसिंक्रोनस रिट्रीवल का इस्तेमाल किया। लेकिन जब से मुझे कभी-कभी इंटरनेट तक पहुंच के बिना कंप्यूटर पर काम करने की आवश्यकता होती है, और मैं हर बार उदाहरणों को फिर से लिखना नहीं चाहता हूं, इस उपकरण का उपयोग करने के लिए विचार उत्पन्न हुआ। इसके अलावा, इकाई परीक्षण का एक अच्छा नियम बाहरी संसाधनों (जैसे फाइलें, नेटवर्क कनेक्शन, डेटाबेस) से इसे अलग करना है, क्योंकि अन्यथा ये परीक्षण अब मॉड्यूलर नहीं होंगे, लेकिन एकीकरण होंगे। मैं यह नहीं कह रहा हूं कि एकीकरण परीक्षण खराब हैं, नहीं, यह अच्छा है, लेकिन यूनिट परीक्षणों में हम अपने कोड पर ध्यान केंद्रित कर सकते हैं, जबकि एकीकरण परीक्षणों में इन बाहरी संसाधनों की उपस्थिति और सामान्य संचालन की आवश्यकता होती है।
मान लें कि हमारे पास कुछ
WebRequestor वर्ग है जो एक वेब पेज एक्सेस करता है और प्रतिक्रिया की लंबाई प्रिंट करता है:
public class WebRequester
{
public void RequestWebPage( string url)
{
var request = WebRequest.Create(url);
var response = request.GetResponse();
Console .WriteLine( "Sync version. URL: {0}, Response content length: {1}" ,
url, response.ContentLength);
}
}
* This source code was highlighted with Source Code Highlighter .
इससे पहले कि हम परीक्षण लिखना शुरू करें, हमें
WebRequest वर्ग के लिए मोल्स उत्पन्न करने की आवश्यकता है। इसके लिए, यह परीक्षण परियोजना में सिस्टम असेंबली पर राइट-क्लिक करने के लिए पर्याप्त है (क्योंकि यह वर्ग इसमें स्थित है), "Moles असेंबली जोड़ें" मेनू आइटम का चयन करें, फिर परीक्षण के साथ प्रोजेक्ट को पुन: व्यवस्थित करें, जिसके परिणामस्वरूप System.Behaviors.dll असेंबली प्रोजेक्ट में दिखाई देती है , मूल System.dll विधानसभा के सभी आवश्यक स्टब्स और मॉल के साथ।
अब देखते हैं कि हम अपने कोड का परीक्षण कैसे कर सकते हैं:
[TestMethod]
[HostType( "Moles" )]
public void RequestWebPageTest()
{
var mole = new System.Net.Moles.MHttpWebResponse();
mole.ContentLengthGet = () => 5;
// URL-.
// , :
//System.Net.Moles.MHttpWebRequest.AllInstances.GetResponse = (r) =>
// {
// if (r.RequestUri == new Uri("http://rsdn.ru"))
// return mole;
// return r.GetResponse();
// };
//
System.Net.Moles.MHttpWebRequest.AllInstances.GetResponse = (r) => mole;
WebRequester target = new WebRequester();
target.RequestWebPage( "http://rsdn.ru" );
}
* This source code was highlighted with Source Code Highlighter .
इस परीक्षण में, हम सबसे पहले
HttpWebResponse वर्ग के लिए एक स्टब बनाते हैं, जो System.Net में स्थित है।
M HttpWebRespoonse नाम के साथ कुछ
नेमस्पेस , और
ContentLength संपत्ति के "बॉडी" के रूप में, हम अपने लैम्ब्डा को
हथेली पर रखते हैं जो
5 रिटर्न करता है। अब हम
GetResponse प्रतिनिधि की स्थापना करके
HttpWebRequest वर्ग के सभी उदाहरणों के लिए
GetResponse विधि को "संशोधित" करते हैं। उसके बाद, हम सुरक्षित रूप से
WebRequester वर्ग के
रिक्वेस्टपेज विधि को कॉल कर सकते हैं और एक सामान्य परिणाम प्राप्त कर सकते हैं, यहां तक कि इंटरनेट तक पहुंच के बिना:
सिंक संस्करण। URL: rsdn.ru , प्रतिक्रिया सामग्री की लंबाई: 5।अब वेब पेज की सामग्री को पुनः प्राप्त करने के अतुल्यकालिक संस्करण पर चलते हैं,
WebRequester वर्ग का
RequestWebPageAsync विधि:
public void RequestWebPageAsync( string url)
{
var waiter = new ManualResetEvent( false );
var request = WebRequest.Create(url);
request.BeginGetResponse(
ar=>
{
var response = request.EndGetResponse(ar);
Console .WriteLine( "Async version. URL: {0}, Response content length: {1}" ,
url, response.ContentLength);
waiter.Set();
}, null );
waiter.WaitOne();
}
* This source code was highlighted with Source Code Highlighter .
परीक्षण उद्देश्यों के लिए, मैं नहीं चाहता कि एसिंक्रोनस ऑपरेशन पूरा होने से पहले नियंत्रण पूरा करने का तरीका। इस कोड में, हम
AsyncResult.AsyncWaitHandle का उपयोग करके नहीं कर सकते हैं
BeginGetResponse विधि द्वारा लौटाया गया, क्योंकि
RequestWebPageAsync विधि
अनुरोध तक जारी रख सकती है। इसके परिणामस्वरूप, ऐसे "अतुल्यकालिक" से कोई मतलब नहीं है, लेकिन यह महत्वपूर्ण नहीं है, क्योंकि यहां मैं केवल अतुल्यकालिक संचालन के परीक्षण के लिए तंत्र दिखाना चाहता हूं और इससे ज्यादा कुछ नहीं। लेकिन मुझे लगता है कि विचार स्पष्ट है।
तो, अब परीक्षण विधि:
[TestMethod]
[HostType( "Moles" )]
public void RequestWebPageAsyncTest()
{
var mole = new System.Net.Moles.MHttpWebResponse();
mole.ContentLengthGet = () => 5;
// ,
//
Action action = () => Thread.Sleep(500);
// , ,
//
// - (-,
// ).
ThreadPool.SetMinThreads(3, 3);
System.Net.Moles.MHttpWebRequest.AllInstances.BeginGetResponseAsyncCallbackObject =
(r, a, iar) => action.BeginInvoke(a, iar);
System.Net.Moles.MHttpWebRequest.AllInstances.EndGetResponseIAsyncResult =
(r, iar) => { action.EndInvoke(iar); return mole; };
WebRequester target = new WebRequester();
target.RequestWebPageAsync(http: //rsdn.ru);
}
* This source code was highlighted with Source Code Highlighter .
हमारे परीक्षण विधि में, हम फिर से
M HttpWebResponse स्टब बनाते हैं, जिसका एक उदाहरण
ContentLength संपत्ति तक पहुंचने पर
5 वापस आ जाएगा, और एक लंबे चलने वाले ऑपरेशन का अनुकरण करने के लिए
थ्रेड सेलेप (500) को कॉल करने वाले प्रतिनिधि का उपयोग करें। निष्पादन के लिए इस परीक्षण को चलाने पर, हमें यह मिलता है:
Async संस्करण। URL: rsdn.ru , प्रतिक्रिया की लंबाई सामग्री: 5. साबित करने के लिए क्या आवश्यक था!
एक निष्कर्ष के बजाय
मोल्स लाइब्रेरी एक बहुत ही दिलचस्प उपकरण है जो आपको अपने इंटरफेस के लिए सरल स्टब्स बनाने में मदद करेगा, और आपको बाहरी संसाधनों, स्थिर या गैर-आभासी तरीकों से अपने कोड को अनटाइट करने की अनुमति देगा, जिसके लिए स्टब्स बनाना एक अन्य तरीके से बस असंभव है। यहां मैंने इस टूल की सभी कार्यक्षमता से बहुत दूर दिखाया है, लेकिन यह समझने के लिए पर्याप्त होना चाहिए कि यह आपके विशिष्ट कार्यों के लिए कितना लागू (या नहीं) है।
प्रोग्रामिंग स्टफ के माध्यम से।