मैं इकाई परीक्षण के लिए नया हूं, और मैं लगातार बहुत से फेंके गए शब्द 'नकली वस्तुएं' सुनता हूं। आम आदमी की शर्तों में, क्या कोई समझा सकता है कि मॉक ऑब्जेक्ट्स क्या हैं, और यूनिट टेस्ट लिखते समय उनका आमतौर पर क्या उपयोग किया जाता है?
मैं इकाई परीक्षण के लिए नया हूं, और मैं लगातार बहुत से फेंके गए शब्द 'नकली वस्तुएं' सुनता हूं। आम आदमी की शर्तों में, क्या कोई समझा सकता है कि मॉक ऑब्जेक्ट्स क्या हैं, और यूनिट टेस्ट लिखते समय उनका आमतौर पर क्या उपयोग किया जाता है?
जवाबों:
चूंकि आप कहते हैं कि आप इकाई परीक्षण के लिए नए हैं और "आम आदमी की शर्तों" में नकली वस्तुओं के लिए कहा है, इसलिए मैं एक आम आदमी के उदाहरण की कोशिश करूँगा।
इस प्रणाली के लिए इकाई परीक्षण की कल्पना करें:
cook <- waiter <- customer
निम्न-स्तरीय घटक की तरह परीक्षण की कल्पना करना आम तौर पर आसान है cook
:
cook <- test driver
परीक्षण चालक बस विभिन्न व्यंजनों का आदेश देता है और सत्यापित करता है कि रस प्रत्येक क्रम के लिए सही व्यंजन देता है।
वेटर की तरह एक मध्य घटक का परीक्षण करना कठिन है, जो अन्य घटकों के व्यवहार का उपयोग करता है। एक भोले परीक्षक वेटर घटक का उसी तरह परीक्षण कर सकता है जिस तरह से हमने कुक घटक का परीक्षण किया था:
cook <- waiter <- test driver
परीक्षण चालक विभिन्न व्यंजनों का आदेश देगा और यह सुनिश्चित करेगा कि वेटर सही पकवान लौटाए। दुर्भाग्य से, इसका मतलब है कि वेटर घटक का यह परीक्षण कुक घटक के सही व्यवहार पर निर्भर हो सकता है। यह निर्भरता और भी खराब है अगर कुक घटक में कोई भी परीक्षण-अमित्र विशेषताएँ होती हैं, जैसे गैर-निर्धारक व्यवहार (मेनू में पकवान के रूप में शेफ का आश्चर्य शामिल है), बहुत सारी निर्भरता (कुक अपने पूरे स्टाफ के बिना नहीं पकाना होगा), या बहुत संसाधनों (कुछ व्यंजनों को महंगी सामग्री की आवश्यकता होती है या पकाने के लिए एक घंटे का समय लगता है)।
चूंकि यह वेटर टेस्ट है, आदर्श रूप से, हम सिर्फ वेटर का परीक्षण करना चाहते हैं, न कि कुक का। विशेष रूप से, हम यह सुनिश्चित करना चाहते हैं कि वेटर ग्राहक के ऑर्डर को सही ढंग से पकाने का संदेश देता है और कस्टमर को कुक का खाना सही तरीके से डिलीवर करता है।
यूनिट टेस्टिंग का अर्थ है स्वतंत्र रूप से यूनिट्स का परीक्षण करना, इसलिए एक बेहतर तरीका यह होगा कि परीक्षण (वेटर) के तहत कंपोनेंट को अलग किया जाए, जो कि फाउलर टेस्ट डबल्स (डमी, स्टब्स, फेक, मॉक) का उपयोग करता है ।
-----------------------
| |
v |
test cook <- waiter <- test driver
यहाँ, टेस्ट कुक को टेस्ट ड्राइवर के साथ "cahoots में" है। आदर्श रूप से, परीक्षण के तहत प्रणाली को डिज़ाइन किया गया है ताकि उत्पादन कोड को बदलने के बिना वेटर के साथ काम करने के लिए टेस्ट कुक को आसानी से प्रतिस्थापित ( इंजेक्ट किया जा सके ) (जैसे वेटर कोड को बदले बिना)।
अब, टेस्ट कुक (टेस्ट डबल) को विभिन्न तरीकों से लागू किया जा सकता है:
नकली बनाम स्टब बनाम मॉक बनाम डमी के बारे में अधिक बारीकियों के लिए फाउलर का लेख देखें , लेकिन अभी के लिए, मॉक कुक पर ध्यान दें।
-----------------------
| |
v |
mock cook <- waiter <- test driver
वेटर घटक का परीक्षण करने वाली इकाई का एक बड़ा हिस्सा इस बात पर केंद्रित है कि वेटर कुक घटक के साथ कैसे इंटरैक्ट करता है। एक मॉक-आधारित दृष्टिकोण पूरी तरह से निर्दिष्ट करने पर ध्यान केंद्रित करता है कि सही बातचीत क्या है और यह पता लगाता है कि यह कब गड़बड़ा जाता है।
मॉक ऑब्जेक्ट पहले से जानता है कि परीक्षण के दौरान क्या होना चाहिए (जैसे इसके कौन से तरीके कॉल किए जाएंगे, इत्यादि) और मॉक ऑब्जेक्ट जानता है कि यह कैसे प्रतिक्रिया करने के लिए माना जाता है (जैसे कि वापसी मूल्य क्या प्रदान करना है)। मॉक यह संकेत देगा कि क्या वास्तव में होता है जो कि होने वाला है, उससे भिन्न होता है। उस परीक्षण मामले के लिए अपेक्षित व्यवहार को निष्पादित करने के लिए प्रत्येक परीक्षण मामले के लिए एक कस्टम मॉक ऑब्जेक्ट को खरोंच से बनाया जा सकता है, लेकिन इस तरह के व्यवहार विनिर्देश को स्पष्ट रूप से और आसानी से परीक्षण के मामले में सीधे इंगित करने की अनुमति देने के लिए एक नकली रूपरेखा प्रयास करता है।
मॉक-आधारित परीक्षण के आसपास की बातचीत इस तरह दिख सकती है:
टेस्ट ड्राइवर को मॉक कुक : एक हॉट डॉग ऑर्डर की उम्मीद करें और जवाब में उसे यह डमी हॉट डॉग दें
वेटर के लिए टेस्ट ड्राइवर (ग्राहक के रूप में प्रस्तुत करना) : मैं हॉट डॉग को पसंद करूँगा
वेटर टू मॉक कुक : 1 हॉट डॉग प्लीज़
मॉक कुक टू वेटर : ऑर्डर अप: 1 हॉट डॉग रेडी (डमी हॉट डॉग टू वेटर)
वेटर को टेस्ट करने के लिए वेटर : यहाँ आपका हॉट डॉग है (ड्राइवर को टेस्ट करने के लिए डमी हॉट डॉग देता है)परीक्षण चालक : परीक्षण सफल!
लेकिन चूंकि हमारा वेटर नया है, इसलिए यह हो सकता है:
टेस्ट ड्राइवर को मॉक कुक : एक हॉट डॉग ऑर्डर की उम्मीद करें और जवाब में उसे यह डमी हॉट डॉग दें
वेटर को टेस्ट ड्राइवर (ग्राहक के रूप में प्रस्तुत करना) : मैं हॉट डॉग की तरह खाना पकाने के लिए
वेटर से बात करूंगा : 1 हैमबर्गर कृपया मॉक कुक टेस्ट को रोक देता है: मुझे हॉट डॉग ऑर्डर की उम्मीद थी!
परीक्षण चालक समस्या नोट करता है: परीक्षण विफल! - वेटर ने ऑर्डर बदल दिया
या
टेस्ट ड्राइवर को मॉक कुक : एक हॉट डॉग ऑर्डर की उम्मीद करें और जवाब में उसे यह डमी हॉट डॉग दें
वेटर के लिए टेस्ट ड्राइवर (ग्राहक के रूप में प्रस्तुत करना) : मैं हॉट डॉग को पसंद करूँगा
वेटर टू मॉक कुक : 1 हॉट डॉग प्लीज़
मॉक कुक टू वेटर : ऑर्डर अप: 1 हॉट डॉग रेडी (डमी हॉट डॉग टू वेटर)
वेटर को टेस्ट करने के लिए वेटर : यहाँ आपका फ्रेंच फ्राइज़ है (ड्राइवर को टेस्ट करने के लिए किसी अन्य ऑर्डर से फ्रेंच फ्राइज़ देता है)परीक्षण चालक अप्रत्याशित फ्रेंच फ्राइज़ नोट करता है: परीक्षण विफल! वेटर ने गलत डिश वापस दे दी
इसके साथ जाने के लिए एक विपरीत स्टब-आधारित उदाहरण के बिना नकली वस्तुओं और स्टब्स के बीच अंतर को स्पष्ट रूप से देखना मुश्किल हो सकता है, लेकिन यह जवाब बहुत पहले से ही है :-)
यह भी ध्यान दें कि यह एक बहुत ही सरल उदाहरण है और यह कि नकली रूपरेखा व्यापक परीक्षणों का समर्थन करने के लिए घटकों से अपेक्षित व्यवहार के कुछ सुंदर परिष्कृत विनिर्देशों के लिए अनुमति देता है। अधिक जानकारी के लिए नकली वस्तुओं और नकली रूपरेखा पर बहुत सारी सामग्री है।
एक मॉक ऑब्जेक्ट एक ऐसी वस्तु है जो एक वास्तविक वस्तु के लिए विकल्प है। ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग में, नकली ऑब्जेक्ट्स को सिम्युलेटेड ऑब्जेक्ट्स हैं जो नियंत्रित तरीकों से वास्तविक ऑब्जेक्ट्स के व्यवहार की नकल करते हैं।
एक कंप्यूटर प्रोग्रामर आम तौर पर किसी अन्य वस्तु के व्यवहार का परीक्षण करने के लिए एक नकली वस्तु बनाता है, उसी तरह जैसे कि एक कार डिजाइनर वाहन प्रभावों में मानव के गतिशील व्यवहार को अनुकरण करने के लिए क्रैश टेस्ट डमी का उपयोग करता है।
http://en.wikipedia.org/wiki/Mock_object
मॉक ऑब्जेक्ट आपको डेटाबेस जैसे बड़े, अनछुए संसाधनों को सहन करने के लिए बिना परीक्षण परिदृश्य सेट करने की अनुमति देते हैं। परीक्षण के लिए डेटाबेस को कॉल करने के बजाय, आप अपने यूनिट परीक्षणों में एक नकली वस्तु का उपयोग करके अपने डेटाबेस का अनुकरण कर सकते हैं। यह आपको एक वास्तविक डेटाबेस को सेट करने और फाड़ने के बोझ से मुक्त करता है, बस अपनी कक्षा में एकल विधि का परीक्षण करने के लिए।
शब्द "मॉक" कभी-कभी गलत तरीके से "ठूंठ" के साथ परस्पर उपयोग किया जाता है। दो शब्दों के बीच अंतर हैं यहाँ वर्णित हैं। अनिवार्य रूप से, एक मॉक एक स्टब ऑब्जेक्ट है जिसमें परीक्षण के तहत ऑब्जेक्ट / विधि के उचित व्यवहार के लिए अपेक्षाएं (यानी "दावे") भी शामिल हैं।
उदाहरण के लिए:
class OrderInteractionTester...
public void testOrderSendsMailIfUnfilled() {
Order order = new Order(TALISKER, 51);
Mock warehouse = mock(Warehouse.class);
Mock mailer = mock(MailService.class);
order.setMailer((MailService) mailer.proxy());
mailer.expects(once()).method("send");
warehouse.expects(once()).method("hasInventory")
.withAnyArguments()
.will(returnValue(false));
order.fill((Warehouse) warehouse.proxy());
}
}
ध्यान दें कि warehouse
और mailer
नकली वस्तुओं को अपेक्षित परिणामों के साथ क्रमादेशित किया जाता है।
नकली वस्तुएं नकली वस्तुएं हैं जो वास्तविक लोगों के व्यवहार की नकल करती हैं। आमतौर पर आप एक नकली वस्तु लिखते हैं यदि:
एक मॉक ऑब्जेक्ट टेस्ट डबल का एक प्रकार है । आप अन्य वर्गों के साथ परीक्षण के तहत वर्ग के प्रोटोकॉल / इंटरैक्शन को जांचने और सत्यापित करने के लिए मॉकबॉजेक्ट का उपयोग कर रहे हैं।
आमतौर पर आप 'प्रोग्राम' या 'रिकॉर्ड' अपेक्षाओं को पसंद करेंगे: विधि कॉल आपको एक अंतर्निहित वस्तु के लिए अपने वर्ग की अपेक्षा करती है।
उदाहरण के लिए मान लें कि हम किसी विजेट में फ़ील्ड अपडेट करने के लिए एक सेवा पद्धति का परीक्षण कर रहे हैं। और यह कि आपकी वास्तुकला में एक विजेट है जो डेटाबेस से संबंधित है। डेटाबेस के साथ बात करना धीमा है और इसे स्थापित करना और बाद में सफाई करना जटिल है, इसलिए हम WidgetDao का मजाक उड़ाएंगे।
आइए विचार करें कि सेवा को क्या करना चाहिए: इसे डेटाबेस से एक विजेट प्राप्त करना चाहिए, इसके साथ कुछ करना चाहिए और इसे फिर से सहेजना चाहिए।
इसलिए छद्म भाषा में छद्म-नकली पुस्तकालय के साथ हमारे पास कुछ ऐसा होगा:
Widget sampleWidget = new Widget();
WidgetDao mock = createMock(WidgetDao.class);
WidgetService svc = new WidgetService(mock);
// record expected calls on the dao
expect(mock.getById(id)).andReturn(sampleWidget);
expect(mock.save(sampleWidget);
// turn the dao in replay mode
replay(mock);
svc.updateWidgetPrice(id,newPrice);
verify(mock); // verify the expected calls were made
assertEquals(newPrice,sampleWidget.getPrice());
इस तरह हम कक्षाओं के विकास को आसानी से परख सकते हैं जो अन्य वर्गों पर निर्भर करते हैं।
मैं मार्टिन फाउलर द्वारा एक बेहतरीन लेख की सलाह देता हूं जिसमें बताया गया है कि वास्तव में क्या हैं और वे स्टब्स से कैसे भिन्न हैं।
जब यूनिट कंप्यूटर प्रोग्राम के कुछ हिस्से का परीक्षण करती है तो आप आदर्श रूप से उस विशेष भाग के व्यवहार का परीक्षण करना चाहते हैं।
उदाहरण के लिए, किसी प्रोग्राम के काल्पनिक टुकड़े से नीचे छद्म कोड को देखें जो प्रिंट प्रोग्राम को कॉल करने के लिए किसी अन्य प्रोग्राम का उपयोग करता है:
If theUserIsFred then
Call Printer(HelloFred)
Else
Call Printer(YouAreNotFred)
End
यदि आप यह परीक्षण कर रहे थे, तो आप मुख्य रूप से उस भाग का परीक्षण करना चाहेंगे जो दिखता है कि उपयोगकर्ता फ्रेड है या नहीं। आप वास्तव Printer
में चीजों के भाग का परीक्षण नहीं करना चाहते हैं। वह एक और परीक्षा होगी।
यह वह जगह है जहां मॉक ऑब्जेक्ट्स आते हैं। वे अन्य प्रकार की चीजों का दिखावा करते हैं। इस मामले में आप एक मॉक का उपयोग करेंगे Printer
ताकि यह वास्तविक प्रिंटर की तरह काम करे, लेकिन मुद्रण जैसी असुविधाजनक चीजें नहीं करेगा।
कई अन्य प्रकार के ढोंग ऑब्जेक्ट हैं जिनका उपयोग आप कर सकते हैं जो Mocks नहीं हैं। मोक्स मोक्स बनाने वाली मुख्य बात यह है कि उन्हें व्यवहार और उम्मीदों के साथ कॉन्फ़िगर किया जा सकता है।
उम्मीदें आपके मॉक को गलत तरीके से उपयोग करने पर त्रुटि उत्पन्न करने देती हैं। इसलिए उपरोक्त उदाहरण में, आप यह सुनिश्चित कर सकते हैं कि प्रिंटर को "उपयोगकर्ता फ्रेड" परीक्षण मामले में हैलोफ्रेड के साथ कहा जाता है। अगर ऐसा नहीं होता है तो आपका मॉक आपको चेतावनी दे सकता है।
मोक्स में व्यवहार का मतलब है कि उदाहरण के लिए, आपके कोड ने कुछ ऐसा किया:
If Call Printer(HelloFred) Returned SaidHello Then
Do Something
End
अब आप परीक्षण करना चाहते हैं कि प्रिंटर को कॉल करने पर आपका कोड क्या करता है और SaidHello को वापस करता है, इसलिए आप SaidHello को वापस करने के लिए Mock सेट कर सकते हैं जब इसे HelloFred के साथ बुलाया जाता है।
इसके आसपास एक अच्छा संसाधन मार्टिन फाउलर्स पोस्ट मोक्स आर स्टब्स नहीं हैं
मॉक और स्टब ऑब्जेक्ट्स यूनिट टेस्टिंग का एक महत्वपूर्ण हिस्सा हैं। वास्तव में वे यह सुनिश्चित करने के लिए एक लंबा रास्ता तय करते हैं कि आप समूहों के बजाय इकाइयों का परीक्षण कर रहे हैं के ।
संक्षेप में, आप SUT को तोड़ने के लिए स्टब्स का उपयोग करते हैं (सिस्टम अंडर टेस्ट) अन्य वस्तुओं पर निर्भरता और ऐसा करने के लिए मॉक और यह सत्यापित करते हैं कि SUT ने निर्भरता पर कुछ विधियों / गुणों को बुलाया। यह इकाई परीक्षण के मूल सिद्धांतों पर वापस जाता है - कि परीक्षणों को आसानी से पठनीय, तेज और विन्यास की आवश्यकता नहीं होनी चाहिए, जो सभी वास्तविक वर्गों का उपयोग कर सकते हैं।
आम तौर पर, आपके परीक्षण में एक से अधिक स्टब हो सकते हैं, लेकिन आपके पास केवल एक नकली होना चाहिए। ऐसा इसलिए है क्योंकि नकली का उद्देश्य व्यवहार को सत्यापित करना है और आपके परीक्षण को केवल एक चीज का परीक्षण करना चाहिए।
C # और Moq का उपयोग करके सरल परिदृश्य:
public interface IInput {
object Read();
}
public interface IOutput {
void Write(object data);
}
class SUT {
IInput input;
IOutput output;
public SUT (IInput input, IOutput output) {
this.input = input;
this.output = output;
}
void ReadAndWrite() {
var data = input.Read();
output.Write(data);
}
}
[TestMethod]
public void ReadAndWriteShouldWriteSameObjectAsRead() {
//we want to verify that SUT writes to the output interface
//input is a stub, since we don't record any expectations
Mock<IInput> input = new Mock<IInput>();
//output is a mock, because we want to verify some behavior on it.
Mock<IOutput> output = new Mock<IOutput>();
var data = new object();
input.Setup(i=>i.Read()).Returns(data);
var sut = new SUT(input.Object, output.Object);
//calling verify on a mock object makes the object a mock, with respect to method being verified.
output.Verify(o=>o.Write(data));
}
उपरोक्त उदाहरण में मैंने स्टेक और मोक्स को प्रदर्शित करने के लिए Moq का उपयोग किया। Moq दोनों के लिए एक ही वर्ग का उपयोग करता है - Mock<T>
जो इसे थोड़ा भ्रमित करता है। भले ही, रनटाइम के दौरान, परीक्षण विफल हो जाएगा यदि output.Write
डेटा के रूप में नहीं कहा जाता है parameter
, जबकि कॉल करने में विफलता input.Read()
इसे विफल नहीं करेगी।
एक और जवाब के रूप में एक लिंक के माध्यम से सुझाव दिया " मोज़ेक स्टब्स नहीं हैं " के , नकली एक वास्तविक वस्तु के बदले में उपयोग करने के लिए "टेस्ट डबल" का एक रूप है। उन्हें टेस्ट डबल्स के अन्य रूपों से अलग बनाता है, जैसे कि स्टब ऑब्जेक्ट्स, यह है कि अन्य टेस्ट डबल्स राज्य सत्यापन (और वैकल्पिक रूप से सिमुलेशन) की पेशकश करते हैं जबकि मोक्स व्यवहार सत्यापन (और वैकल्पिक रूप से सिमुलेशन) की पेशकश करते हैं।
एक स्टब के साथ, आप स्टब पर कई तरीकों को किसी भी क्रम में (या यहां तक कि दोहराव से) बुला सकते हैं और सफलता का निर्धारण कर सकते हैं यदि स्टब ने एक मूल्य या आपके इच्छित राज्य पर कब्जा कर लिया है। इसके विपरीत, एक नकली वस्तु एक विशिष्ट क्रम में, और यहां तक कि एक विशिष्ट संख्या में भी बहुत विशिष्ट कार्यों की अपेक्षा करती है। एक मॉक ऑब्जेक्ट के साथ परीक्षण को "विफल" माना जाएगा, क्योंकि विधियों को एक अलग अनुक्रम या गिनती में लगाया गया था - भले ही परीक्षण के समापन पर नकली वस्तु की सही स्थिति थी!
इस प्रकार, नकली वस्तुओं की तुलना में नकली वस्तुओं को अक्सर SUT कोड में अधिक कसकर जोड़ा जाता है। जो आप सत्यापित करने का प्रयास कर रहे हैं, उसके आधार पर यह एक अच्छी या बुरी चीज हो सकती है।
नकली वस्तुओं का उपयोग करने के बिंदु का एक हिस्सा यह है कि उन्हें वास्तव में कल्पना के अनुसार लागू करने की आवश्यकता नहीं है। वे सिर्फ डमी प्रतिक्रिया दे सकते हैं। उदाहरण के लिए यदि आपको ए और बी के घटकों को लागू करना है, और दोनों "कॉल" (एक दूसरे के साथ बातचीत) करते हैं, तो आप बी को लागू होने तक ए का परीक्षण नहीं कर सकते हैं, और इसके विपरीत। परीक्षण-संचालित विकास में, यह एक समस्या है। तो आप A और B के लिए नकली ("डमी") ऑब्जेक्ट बनाते हैं, जो बहुत ही सरल हैं, लेकिन जब वे आपस में बातचीत करते हैं, तो वे किसी प्रकार की प्रतिक्रिया देते हैं। इस तरह, आप बी के लिए एक नकली वस्तु का उपयोग करके ए को लागू और परीक्षण कर सकते हैं।
Php और phpunit के लिए phpunit documentaion में अच्छी तरह से समझाया गया है। यहाँ देखें फ़पुनिट प्रलेखन
सरल शब्द में मॉकिंग ऑब्जेक्ट आपके मूल के सिर्फ डमी ऑब्जेक्ट है और उसका रिटर्न मान है, इस रिटर्न वैल्यू का उपयोग टेस्ट क्लास में किया जा सकता है
यह इकाई परीक्षणों के मुख्य दृष्टिकोणों में से एक है। हां, आप कोड की अपनी एकल इकाई का परीक्षण करने का प्रयास कर रहे हैं और आपके परीक्षा परिणाम अन्य सेम या ऑब्जेक्ट व्यवहार के लिए प्रासंगिक नहीं होने चाहिए। तो आप उन्हें कुछ सरल इसी प्रतिक्रिया के साथ नकली वस्तुओं का उपयोग करके उनका मजाक उड़ाएं।