मैं नकली परीक्षण में मॉक, स्टब और स्पाई के बीच के अंतर को नहीं समझता और जिन ट्यूटोरियल को मैं ऑनलाइन देख रहा हूं, उन्हें विस्तार से नहीं समझाता।
मैं नकली परीक्षण में मॉक, स्टब और स्पाई के बीच के अंतर को नहीं समझता और जिन ट्यूटोरियल को मैं ऑनलाइन देख रहा हूं, उन्हें विस्तार से नहीं समझाता।
जवाबों:
ध्यान दें: मैं देखरेख करने जा रहा हूं और शायद आने वाले पैराग्राफ में थोड़ा सा गलत भी हो सकता है। अधिक विस्तृत जानकारी के लिए मार्टिन फाउलर की वेबसाइट देखें ।
एक नकली एक डमी वर्ग है जो एक वास्तविक की जगह लेता है, प्रत्येक विधि कॉल के लिए नल या 0 जैसी कुछ लौटाता है। यदि आप किसी जटिल वर्ग के डमी उदाहरण की जरूरत है, जो नेटवर्क कनेक्शन, फाइल या डेटाबेस जैसे बाहरी संसाधनों का उपयोग करते हैं या शायद दर्जनों अन्य वस्तुओं का उपयोग करते हैं, तो आप एक नकली का उपयोग करते हैं। मोक्स का लाभ यह है कि आप परीक्षण के बाकी वर्ग से वर्ग को अलग कर सकते हैं।
एक स्टब भी एक डमी वर्ग है जो परीक्षण के तहत कुछ विशिष्ट अनुरोधों के लिए कुछ और अधिक विशिष्ट, तैयार या पूर्व-रिकॉर्ड किए गए पुन: परिणाम प्रदान करता है। आप कह सकते हैं कि एक स्टब एक फैंसी नकली है। स्पॉक में आप अक्सर स्टब के तरीकों के बारे में पढ़ेंगे।
एक स्पाई वास्तविक वस्तु और स्टब के बीच एक प्रकार का संकर है, अर्थात यह मूल रूप से स्टब विधियों द्वारा छायांकित कुछ (सभी नहीं) विधियों के साथ वास्तविक वस्तु है। गैर-स्टब किए गए तरीके मूल ऑब्जेक्ट के माध्यम से रूट किए जाते हैं। इस तरह से आप "सस्ते" या तुच्छ तरीकों के लिए मूल व्यवहार कर सकते हैं और "महंगी" या जटिल तरीकों के लिए नकली व्यवहार कर सकते हैं।
अद्यतन 2017-02-06: वास्तव में उपयोगकर्ता मिखाइल का उत्तर मेरे मूल से ऊपर स्पॉक के लिए अधिक विशिष्ट है। तो Spock के दायरे में, वह जो वर्णन करता है वह सही है, लेकिन यह मेरे सामान्य उत्तर को गलत नहीं ठहराता है:
अब यहां एक निष्पादन योग्य उदाहरण परीक्षण है, जो यह दर्शाता है कि क्या संभव है और क्या नहीं है। यह मिखाइल के स्निपेट्स की तुलना में थोड़ा अधिक शिक्षाप्रद है। मेरे खुद के जवाब में सुधार करने के लिए मुझे प्रेरणा देने के लिए बहुत धन्यवाद! :-)
package de.scrum_master.stackoverflow
import org.spockframework.mock.TooFewInvocationsError
import org.spockframework.runtime.InvalidSpecException
import spock.lang.FailsWith
import spock.lang.Specification
class MockStubSpyTest extends Specification {
static class Publisher {
List<Subscriber> subscribers = new ArrayList<>()
void addSubscriber(Subscriber subscriber) {
subscribers.add(subscriber)
}
void send(String message) {
for (Subscriber subscriber : subscribers)
subscriber.receive(message);
}
}
static interface Subscriber {
String receive(String message)
}
static class MySubscriber implements Subscriber {
@Override
String receive(String message) {
if (message ==~ /[A-Za-z ]+/)
return "ok"
return "uh-oh"
}
}
Subscriber realSubscriber1 = new MySubscriber()
Subscriber realSubscriber2 = new MySubscriber()
Publisher publisher = new Publisher(subscribers: [realSubscriber1, realSubscriber2])
def "Real objects can be tested normally"() {
expect:
realSubscriber1.receive("Hello subscribers") == "ok"
realSubscriber1.receive("Anyone there?") == "uh-oh"
}
@FailsWith(TooFewInvocationsError)
def "Real objects cannot have interactions"() {
when:
publisher.send("Hello subscribers")
publisher.send("Anyone there?")
then:
2 * realSubscriber1.receive(_)
}
def "Stubs can simulate behaviour"() {
given:
def stubSubscriber = Stub(Subscriber) {
receive(_) >>> ["hey", "ho"]
}
expect:
stubSubscriber.receive("Hello subscribers") == "hey"
stubSubscriber.receive("Anyone there?") == "ho"
stubSubscriber.receive("What else?") == "ho"
}
@FailsWith(InvalidSpecException)
def "Stubs cannot have interactions"() {
given: "stubbed subscriber registered with publisher"
def stubSubscriber = Stub(Subscriber) {
receive(_) >> "hey"
}
publisher.addSubscriber(stubSubscriber)
when:
publisher.send("Hello subscribers")
publisher.send("Anyone there?")
then:
2 * stubSubscriber.receive(_)
}
def "Mocks can simulate behaviour and have interactions"() {
given:
def mockSubscriber = Mock(Subscriber) {
3 * receive(_) >>> ["hey", "ho"]
}
publisher.addSubscriber(mockSubscriber)
when:
publisher.send("Hello subscribers")
publisher.send("Anyone there?")
then: "check interactions"
1 * mockSubscriber.receive("Hello subscribers")
1 * mockSubscriber.receive("Anyone there?")
and: "check behaviour exactly 3 times"
mockSubscriber.receive("foo") == "hey"
mockSubscriber.receive("bar") == "ho"
mockSubscriber.receive("zot") == "ho"
}
def "Spies can have interactions"() {
given:
def spySubscriber = Spy(MySubscriber)
publisher.addSubscriber(spySubscriber)
when:
publisher.send("Hello subscribers")
publisher.send("Anyone there?")
then: "check interactions"
1 * spySubscriber.receive("Hello subscribers")
1 * spySubscriber.receive("Anyone there?")
and: "check behaviour for real object (a spy is not a mock!)"
spySubscriber.receive("Hello subscribers") == "ok"
spySubscriber.receive("Anyone there?") == "uh-oh"
}
def "Spies can modify behaviour and have interactions"() {
given:
def spyPublisher = Spy(Publisher) {
send(_) >> { String message -> callRealMethodWithArgs("#" + message) }
}
def mockSubscriber = Mock(MySubscriber)
spyPublisher.addSubscriber(mockSubscriber)
when:
spyPublisher.send("Hello subscribers")
spyPublisher.send("Anyone there?")
then: "check interactions"
1 * mockSubscriber.receive("#Hello subscribers")
1 * mockSubscriber.receive("#Anyone there?")
}
}
प्रश्न स्पॉक फ्रेमवर्क के संदर्भ में था और मुझे विश्वास नहीं है कि वर्तमान उत्तर इसे ध्यान में रखते हैं।
स्पॉक डॉक्स के आधार पर (उदाहरण के लिए अनुकूलित, मेरा अपना शब्द जोड़ा गया):
स्टब: सहयोगियों को एक निश्चित तरीके से विधि कॉल का जवाब देने के लिए उपयोग किया जाता है। जब एक विधि को ठोकर मारते हैं, तो आप परवाह नहीं करते हैं कि क्या और कितनी बार विधि कहा जा रहा है; आप बस यह चाहते हैं कि जब भी यह कहा जाए, कुछ मूल्य लौटाएं, या कुछ दुष्प्रभाव करें।
subscriber.receive(_) >> "ok" // subscriber is a Stub()
मॉक: विनिर्देश और उसके सहयोगियों के तहत वस्तु के बीच बातचीत का वर्णन करने के लिए उपयोग किया जाता है।
def "should send message to subscriber"() {
when:
publisher.send("hello")
then:
1 * subscriber.receive("hello") // subscriber is a Mock()
}
एक नकली एक नकली और एक ठूंठ के रूप में कार्य कर सकता है:
1 * subscriber.receive("message1") >> "ok" // subscriber is a Mock()
जासूसी: हमेशा वास्तविक चीजों पर आधारित वास्तविक वस्तु पर आधारित होती है जो वास्तविक चीजें करती हैं। चुनिंदा तरीकों के रिटर्न वैल्यू को बदलने के लिए स्टब की तरह इस्तेमाल किया जा सकता है। बातचीत का वर्णन करने के लिए एक मॉक की तरह इस्तेमाल किया जा सकता है।
def subscriber = Spy(SubscriberImpl, constructorArgs: ["Fred"])
def "should send message to subscriber"() {
when:
publisher.send("hello")
then:
1 * subscriber.receive("message1") >> "ok" // subscriber is a Spy(), used as a Mock an Stub
}
def "should send message to subscriber (actually handle 'receive')"() {
when:
publisher.send("hello")
then:
1 * subscriber.receive("message1") // subscriber is a Spy(), used as a Mock, uses real 'receive' function
}
सारांश:
स्टोक () पर्याप्त है तो मॉक () का उपयोग करने से बचें।
जासूस () का उपयोग करने से बचें, यदि आप ऐसा कर सकते हैं, तो एक गंध और गलत परीक्षण या परीक्षण के तहत वस्तु के गलत डिजाइन पर संकेत हो सकता है।
समान्य शब्दों में:
मॉक: आप एक प्रकार का मजाक करते हैं और मक्खी पर आपको एक वस्तु बनाई जाती है। इस नकली वस्तु के तरीके रिटर्न प्रकार के डिफ़ॉल्ट मान लौटाते हैं।
स्टब: आप एक स्टब क्लास बनाते हैं जहाँ तरीकों को आपकी आवश्यकता के अनुसार परिभाषा के साथ पुनर्परिभाषित किया जाता है। Ex: वास्तविक ऑब्जेक्ट विधि में आप कॉल करते हैं और बाहरी एपीआई करते हैं और उपयोगकर्ता नाम और आईडी को वापस करते हैं। स्टबड ऑब्जेक्ट विधि में आप कुछ डमी नाम वापस करते हैं।
जासूस: आप एक असली वस्तु बनाते हैं और फिर आप उसकी जासूसी करते हैं। अब आप कुछ तरीकों का मजाक उड़ा सकते हैं और कुछ के लिए ऐसा नहीं करने का विकल्प चुना।
एक उपयोग अंतर यह है कि आप विधि स्तर की वस्तुओं का मजाक नहीं उड़ा सकते। जब आप विधि में एक डिफ़ॉल्ट ऑब्जेक्ट बना सकते हैं और तब जासूसी वस्तु में तरीकों का वांछित व्यवहार प्राप्त करने के लिए उस पर जासूसी कर सकते हैं।
स्टब्स वास्तव में केवल इकाई परीक्षण की सुविधा के लिए हैं, वे परीक्षण का हिस्सा नहीं हैं। मोक्स, परीक्षण का हिस्सा, सत्यापन का हिस्सा, पास / असफल का हिस्सा हैं।
तो, मान लीजिए कि आपके पास एक ऐसी विधि है जो एक पैरामीटर के रूप में किसी ऑब्जेक्ट में ले जाती है। आप कभी भी ऐसा कुछ नहीं करते हैं जो परीक्षण में इस पैरामीटर को बदलता है। आप बस इससे एक मान पढ़ते हैं। वह एक ठूंठ है।
यदि आप कुछ भी बदलते हैं, या ऑब्जेक्ट के साथ किसी प्रकार की सहभागिता को सत्यापित करने की आवश्यकता है, तो यह एक नकली है।