2015-05-19 3 views
5

मैं अपने आप को इकाई परीक्षण सर्वोत्तम प्रथाओं में एक बहुत प्रशिक्षित करने के लिए हाल ही में की कोशिश की। इसमें से अधिकांश सही समझ में आता है, लेकिन ऐसा कुछ ऐसा होता है जिसे अक्सर अनदेखा किया जाता है और/या बुरी तरह समझाया जाता है: एक यूनिट-टेस्ट सजाए गए कार्यों को कैसे किया जाना चाहिए?सजाए गए कार्यों को यूनिट-टेस्ट कैसे करें?

def stringify(func): 
    @wraps(func) 
    def wrapper(*args): 
     return str(func(*args)) 

    return wrapper 


class A(object): 
    @stringify 
    def add_numbers(self, a, b): 
     """ 
     Returns the sum of `a` and `b` as a string. 
     """ 
     return a + b 

मैं स्पष्ट रूप से निम्नलिखित परीक्षणों लिख सकते हैं::

def test_stringify(): 
    @stringify 
    def func(x): 
     return x 

    assert func(42) == "42" 

def test_A_add_numbers(): 
    instance = MagicMock(spec=A) 
    result = A.add_numbers.__wrapped__(instance, 3, 7) 
    assert result == 10 

यह मैं हूँ 100% कवरेज देता है:

की मैं इस कोड है मान लेते हैं मुझे पता है कि किसी भी समारोह है कि stringify() के साथ सजाया जाता है एक स्ट्रिंग के रूप में अपना परिणाम प्राप्त करता है, और मुझे पता है कि अनावृत A.add_numbers() फ़ंक्शन इसके तर्कों का योग देता है। तो पारगमनशीलता के अनुसार, A.add_numbers() के सजाए गए संस्करण को एक स्ट्रिंग के रूप में अपने तर्क का योग वापस करना होगा। सब अच्छा लगता है!

हालांकि मैं इस से पूरी तरह से संतुष्ट नहीं हूं: मेरे परीक्षण, जैसा कि मैंने उन्हें लिखा था, अभी भी पास हो सकता है अगर मैं एक और सजावट का उपयोग करना चाहता था (जो कुछ और करता है, तो str पर कास्टिंग करने के बजाय परिणाम को गुणा करें) । मेरा फ़ंक्शन A.add_numbers अब और सही नहीं होगा, फिर भी परीक्षण अभी भी पास होंगे। भयानक नहीं

मैं A.add_numbers() का सजाया संस्करण का परीक्षण कर सकता है, लेकिन फिर मैं चीजों overtest के बाद से मेरी डेकोरेटर पहले से ही इकाई परीक्षण है।

यह लगता है जैसे मैं कुछ यहाँ याद कर रहा हूँ। यूनिट-टेस्ट सजाए गए कार्यों के लिए एक अच्छी रणनीति क्या है?

उत्तर

1

मैंने अपने सजावटी को दो में विभाजित कर दिया। तो होने के बजाय:

def stringify(func): 
    @wraps(func) 
    def wrapper(*args): 
     return str(func(*args)) 

    return wrapper 

मेरे पास है:

def to_string(value): 
    return str(value) 

def stringify(func): 
    @wraps(func) 
    def wrapper(*args): 
     return to_string(func(*args)) 

    return wrapper 

कौन सा मुझे बाद में बस नकली बाहर to_string सजाया समारोह का परीक्षण करने के लिए जब अनुमति देता है।

स्पष्ट रूप से इस साधारण उदाहरण के मामले में यह अधिक हो सकता है, लेकिन जब सजावटी पर उपयोग किया जाता है जो वास्तव में कुछ जटिल या महंगा होता है (जैसे डीबी, या जो कुछ भी कनेक्शन खोलना), तो इसे नकल करने में सक्षम होना बहुत ही है अच्छी बात।

0

टेस्ट सार्वजनिक इंटरफ़ेस अपने कोड की। यदि आप केवल लोगों को सजाए गए कार्यों को कॉल करने की उम्मीद करते हैं, तो यही आपको परीक्षण करना चाहिए। यदि सजावटी भी सार्वजनिक है, तो उसे भी जांचें (जैसे आपने test_stringify() के साथ किया था)। लिपटे संस्करणों का परीक्षण न करें जब तक कि लोग उन्हें सीधे कॉल नहीं कर रहे हों।

+0

मुझे विश्वास है कि आप मेरे प्रश्न को थोड़ा तेज़ी से पढ़ते हैं। मैं कार्यात्मक परीक्षण लिखना नहीं चाहता लेकिन यूनिट-टेस्ट। – ereOn

+1

तथ्य यह है कि 'add_numbers' वास्तव में 'स्ट्रिंगफ़ाई' द्वारा सजाए गए एक और फ़ंक्शन एक कार्यान्वयन विवरण है। परीक्षण करें कि 'add_numbers' इरादे के अनुसार काम करता है, और इससे कोई फर्क नहीं पड़ता कि आप एक अलग सजावट (या बिल्कुल सजावट नहीं) का उपयोग करते हैं। – chepner

+0

@chepner: कार्यान्वयन विवरणों का परीक्षण करने के लिए यूनिट-टेस्ट ठीक हैं। फिर, अगर हम कार्यात्मक/एकीकरण परीक्षणों के बारे में बात कर रहे थे तो मैं सहमत होगा। यह सिर्फ ऑफ-विषय है। – ereOn

1

इकाई परीक्षण का बड़ा लाभ यह है कि पुनर्संशोधित कोड एक ही काम करने के लिए के रूप में यह पहले किया था जारी है विश्वास के कुछ डिग्री के साथ पुनर्रचना अनुमति है। मान लीजिए आप

def add_numbers(a, b): 
    return str(a + b) 

def mult_numbers(a, b): 
    return str(a * b) 

साथ शुरू किया था तुम अब

def test_add_numbers(): 
    assert add_numbers(3, 5) == "8" 

def test_mult_numbers(): 
    assert mult_numbers(3, 5) == "15" 

की तरह कुछ परीक्षण के लिए होता है, तो आप, आम प्रत्येक कार्य के कुछ हिस्सों (एक स्ट्रिंग में उत्पादन लपेटकर) refactor करने के लिए अपने stringify डेकोरेटर का उपयोग कर तय ।

def stringify(func): 
    @wraps(func) 
    def wrapper(*args): 
     return str(func(*args)) 

    return wrapper 

@stringify 
def add_numbers(a, b): 
    return a + b 

@stringify 
def mult_numbers(a, b): 
    return a * b 

आप देखेंगे कि आपके मूल परीक्षण इस रिफैक्टरिंग के बाद काम करना जारी रखते हैं। यह कोई फर्क नहीं पड़ता कैसे आप add_numbers और mult_numbers लागू किया; क्या मायने रखता है कि वे परिभाषित के रूप में काम करना जारी रखते हैं: वांछित ऑपरेशन के एक कठोर परिणाम को सुरक्षित करना। एक स्ट्रिंग है, जो आपके test_stringify करता है के रूप में सजाया फ़ंक्शन के परिणाम लौट:

केवल शेष परीक्षण आप जरूरत लिखने के stringify क्या यह करना है करने के लिए क्या करता है कि सत्यापित करने के लिए एक है।


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

+1

मुझे डर है कि मैंने एक उदाहरण चुना जो बहुत आसान था। मेरी चिंता यह है कि यदि 'स्ट्रिंग() 'किसी भी तरह गलत है (कहें कि मैंने' str' के बजाय 'srt' गलत टाइप किया है), अब मेरे सजाए गए कार्यों के सभी परीक्षण विफल हो गए हैं, लेकिन उन्हें नहीं करना चाहिए: उनका कार्यान्वयन ** ** सही है , फिर भी उनके परीक्षण विफल। यह स्वीकार्य नहीं है क्योंकि यह इकाई परीक्षण करने के पूरे बिंदु को हरा देता है। – ereOn

+1

@ereOn: फिर 'stringify() 'के लिए एक अलग परीक्षण लिखें। यह भी असफल हो जाएगा, और फिर आपको पता चलेगा कि यह सजावटी था जो टूट गया था। – Kevin

+0

@ केविन: कई असंबद्ध परीक्षण होने से जो एक-पंक्ति परिवर्तन के लिए असफल होते हैं, यह स्पष्ट रूप से एक संकेत है कि पहले स्थान पर कोई परीक्षण नहीं कर रहा है। इस बहुत ही सरल उदाहरण में यह स्पष्ट होगा कि क्या टूट गया। एक बहुत अधिक जटिल में, इतना नहीं। – ereOn

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

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