आप सही हैं, आपके परीक्षणों को यह सत्यापित नहीं करना चाहिए कि random
मॉड्यूल अपना काम कर रहा है; एक यूनिटेस्ट को केवल कक्षा का ही परीक्षण करना चाहिए, न कि यह अन्य कोड के साथ कैसे इंटरैक्ट करता है (जिसे अलग से परीक्षण किया जाना चाहिए)।
यह पूरी तरह से संभव है कि आपका कोड random.randint()
गलत उपयोग करता है; या आप random.randrange(1, self._sides)
इसके बजाय फोन कर रहे हैं और आपकी मृत्यु कभी भी उच्चतम मूल्य नहीं फेंकती है, लेकिन यह एक अलग तरह का बग होगा, न कि आप जिसे एक सबसे अच्छे तरीके से पकड़ सकते हैं। उस स्थिति में, आपकी die
इकाई डिज़ाइन के रूप में काम कर रही है, लेकिन डिज़ाइन स्वयं त्रुटिपूर्ण था।
इस स्थिति में, मैं फ़ंक्शन को बदलने के लिए मॉकिंग का उपयोग करूंगा randint()
, और केवल यह सत्यापित करूंगा कि इसे सही तरीके से कहा गया है। पायथन 3.3 और अप इस प्रकार के परीक्षण को संभालने के लिए unittest.mock
मॉड्यूल के साथ आता है , लेकिन आप सटीक समान कार्यक्षमता प्राप्त करने के लिए पुराने संस्करणों पर बाहरी mock
पैकेज स्थापित कर सकते हैं
import unittest
try:
from unittest.mock import patch
except ImportError:
# < python 3.3
from mock import patch
@patch('random.randint', return_value=3)
class TestDice(unittest.TestCase):
def _make_one(self, *args, **kw):
from die import Die
return Die(*args, **kw)
def test_standard_size(self, mocked_randint):
die = self._make_one()
result = die.roll()
mocked_randint.assert_called_with(1, 6)
self.assertEqual(result, 3)
def test_custom_size(self, mocked_randint):
die = self._make_one(sides=42)
result = die.roll()
mocked_randint.assert_called_with(1, 42)
self.assertEqual(result, 3)
if __name__ == '__main__':
unittest.main()
मॉकिंग के साथ, आपका परीक्षण अब बहुत सरल है; केवल 2 मामले हैं, वास्तव में। 6-पक्षीय मरने के लिए डिफ़ॉल्ट मामला और कस्टम पक्ष केस।
randint()
वैश्विक नामस्थान में फ़ंक्शन को अस्थायी रूप से प्रतिस्थापित करने के अन्य तरीके हैं Die
, लेकिन mock
मॉड्यूल यह सबसे आसान बनाता है। यहाँ @mock.patch
सज्जाकार परीक्षण के मामले में सभी परीक्षण विधियों पर लागू होता है ; प्रत्येक परीक्षण विधि को एक अतिरिक्त तर्क दिया जाता है, random.randint()
मॉक किए गए फ़ंक्शन, इसलिए हम मॉक के खिलाफ यह देखने के लिए परीक्षण कर सकते हैं कि क्या यह वास्तव में सही रूप से कहा गया है। return_value
तर्क निर्दिष्ट क्या, नकली से दिया जाता है तो हम पुष्टि कर सकते हैं जब यह कहा जाता है die.roll()
विधि वास्तव में हमारे लिए 'यादृच्छिक' परिणाम प्राप्त हुआ।
मैंने यहां एक और पायथन का सबसे अच्छा अभ्यास किया है: परीक्षण के हिस्से के रूप में परीक्षण के तहत कक्षा का आयात करें। _make_one
विधि आयात और इन्स्टेन्शियशन काम करता है एक परीक्षण के भीतर , परीक्षण ताकि मॉड्यूल अभी भी लोड होगा, भले ही आप एक सिंटैक्स त्रुटि या अन्य गलती है कि आयात करने के लिए मूल मॉड्यूल रोक देंगे बना दिया।
इस तरह, यदि आपने मॉड्यूल कोड में ही गलती की है, तो परीक्षण अभी भी चलाए जाएंगे; वे आपके कोड में त्रुटि के बारे में बताते हुए, बस विफल हो जाएंगे।
स्पष्ट होने के लिए, उपरोक्त परीक्षण चरम में सरल हैं। random.randint()
उदाहरण के लिए, यहाँ लक्ष्य को सही तर्कों के साथ परीक्षण करना नहीं है । इसके बजाय, लक्ष्य यह परीक्षण करना है कि इकाई कुछ इनपुटों को देखते हुए सही परिणाम दे रही है, जहां उन इनपुटों में अन्य इकाइयों के परिणाम शामिल हैं जो परीक्षण के तहत नहीं हैं । random.randint()
अपने कोड में सिर्फ एक और इनपुट पर नियंत्रण पाने के लिए विधि का मज़ाक उड़ाकर ।
में असली दुनिया परीक्षण, अपनी यूनिट-अंडर-परीक्षण में वास्तविक कोड और अधिक जटिल होने जा रहा है; एपीआई में पारित इनपुट्स के साथ संबंध और कैसे अन्य इकाइयां हैं, तब भी दिलचस्प हो सकता है, और मॉकिंग आपको मध्यवर्ती परिणामों तक पहुंच देगा, साथ ही साथ आप उन कॉल के लिए रिटर्न मान भी सेट करेंगे।
उदाहरण के लिए, कोड में जो उपयोगकर्ताओं को तृतीय पक्ष OAuth2 सेवा (एक मल्टी-स्टेज इंटरैक्शन) के खिलाफ प्रमाणित करता है, आप यह परीक्षण करना चाहते हैं कि आपका कोड उस 3 पार्टी सेवा के लिए सही डेटा पास कर रहा है, और आपको विभिन्न त्रुटि प्रतिक्रियाओं का मजाक उड़ाता है। 3 पार्टी सेवा वापस आ जाएगी, जिससे आप बिना पूर्ण OAuth2 सर्वर का निर्माण किए विभिन्न परिदृश्यों का अनुकरण कर सकते हैं। यहां यह परीक्षण करना महत्वपूर्ण है कि पहली प्रतिक्रिया से जानकारी को सही तरीके से संभाला गया है और दूसरे चरण के कॉल पर पास किया गया है, इसलिए आप यह देखना चाहते हैं कि नकली सेवा को सही तरीके से कहा जा रहा है।