python - गलत दावे के तरीकों का पता लगा रहा है




unit-testing testing (3)

हाल की कोड समीक्षाओं में से एक के दौरान, मैंने इस समस्या पर ठोकर खाई है, जो तुरंत स्पॉट करने में आसान नहीं था - assertTrue() गया था assertTrue() उपयोग करने के बजाय assertEqual() जो कि मूल रूप से एक परीक्षण के परिणामस्वरूप जो कुछ भी नहीं परीक्षण कर रहा था। यहां एक सरल उदाहरण है:

from unittest import TestCase


class MyTestCase(TestCase):
    def test_two_things_equal(self):
        self.assertTrue("a", "b")

यहां समस्या यह है कि परीक्षा पास होगी; और तकनीकी रूप से, कोड मान्य है, चूंकि assertTrue पास यह वैकल्पिक msg तर्क (इस मामले में "b" मान हो जाता है)।

क्या हम इस तरह की समस्याओं को हल करने के लिए कोड की समीक्षा करने वाले व्यक्ति पर भरोसा करने से बेहतर कर सकते हैं? क्या flake8 या pylint साथ स्टैटिक कोड विश्लेषण का उपयोग करने के लिए स्वयं का पता लगाने का एक तरीका है?


इस प्रकार की समस्या का एक समाधान "उत्परिवर्तन परीक्षण" का उपयोग करना है यह विचार आपके कोड के "म्यूटेंट्स" को स्वचालित रूप से उत्पन्न करने के लिए है, इसमें छोटे बदलाव ला सकते हैं। फिर आपके परीक्षण सूट इन म्यूटेंटों के खिलाफ चलती है और यदि यह अच्छा है तो उनमें से ज्यादातर को मारना चाहिए, जिसका अर्थ है कि आपके परीक्षण सूट में उत्परिवर्तन का पता लगाया जाता है और परीक्षण विफल होते हैं।

उत्परिवर्तन परीक्षण वास्तव में आपके परीक्षणों की गुणवत्ता का मूल्यांकन करता है। आपके उदाहरण में, कोई म्यूटेंट नहीं मारा जाएगा और आप आसानी से पता लगा सकते हैं कि परीक्षण के साथ कुछ गलत है।

अजगर में, कई म्यूटेशन फ्रेमवर्क उपलब्ध हैं:


एक त्वरित समाधान एक मिक्सिन प्रदान करेगा जो सही तरीके से जांचता है:

import unittest


class Mixin(object):
    def assertTrue(self, *args, **kwargs):
        if len(args) > 1:
            # TypeError is just an example, it could also do some warning/logging
            # stuff in here.
            raise TypeError('msg should be given as keyword parameter.')
        super().assertTrue(*args, **kwargs)


class TestMixin(Mixin, unittest.TestCase):  # Mixin before other parent classes
    def test_two_things_equal(self):
        self.assertTrue("a", "b")

मिक्सिन यह भी जांच सकता है कि पारित अभिव्यक्ति एक बूलियन है:

class Mixin(object):
    def assertTrue(self, *args, **kwargs):
        if type(args[0]) is bool:
            raise TypeError('expression should be a boolean')
        if len(args) > 1:
            raise TypeError('msg should be given as keyword parameter.')
        super().assertTrue(*args, **kwargs)

हालांकि यह स्थिर नहीं है और इसे मैन्युअल रूप से अपनी परीक्षण कक्षाओं को बदलना (मिक्सिन जोड़ना) और परीक्षण चलाने की आवश्यकता है साथ ही यह बहुत-बहुत झूठी सकारात्मकता निकाल देगी क्योंकि संदेश-तर्क के रूप में संदेश को गुजरना वास्तव में आम नहीं है (कम से कम नहीं, जहां मैंने इसे देखा है) और कई मामलों में आप अभिव्यक्ति की सत्यता को जांचना चाहते हैं स्पष्ट bool बजाय बिना if a खालीपन की जांच करना, if a एक list , dict , आदि है

आप कुछ assertTrue , assertTrue कोड का भी उपयोग कर सकते हैं जो विशिष्ट श्रेणी के लिए assertTrue विधि बदलता है:

import unittest


def decorator(func):
    def wrapper(*args, **kwargs):
        if len(args) > 1:
            raise TypeError()
        return func(*args, **kwargs)
    return wrapper


class TestMixin(unittest.TestCase):
    def setUp(self):
        self._old = self.assertTrue
        self.assertTrue = decorator(self.assertTrue)

    def tearDown(self):
        self.assertTrue = self._old

    def test_two_things_equal(self):
        self.assertTrue("a", "b")

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


पायथन में अब एक प्रकार का हिंटिंग सिस्टम है जो स्थिर कोड विश्लेषण करता है। इस प्रणाली का प्रयोग करके आपको यह आवश्यक हो सकता है कि किसी भी कार्य के पहले तर्क जैसे assertTrue हमेशा बूलीयन होता है। समस्या यह है कि assertTrue आपके द्वारा परिभाषित नहीं है, लेकिन unittest पैकेज द्वारा। दुर्भाग्य से, एकीकृत पैकेज ने संकेतों को नहीं जोड़ा। इसके आसपास एक यथोचित रूप से आसान तरीका है: बस अपनी खुद की आवरण परिभाषित करें

from unittest import TestCase

class TestCaseWrapper(TestCase):
    def assertTrue(self, expr: bool, msg=None): #The ": bool" requires that the expr parameter is boolean.
        TestCase.assertTrue(self, expr, msg)

class MyTestCase(TestCaseWrapper):
    def test_two_things_equal(self):
        self.assertTrue("a", "b") #Would give a warning about the type of "a".

फिर आप इस तरह के प्रकार चेकर को चला सकते हैं:

python -m mypy my_test_case.py

इसके बाद आपको एक चेतावनी देनी चाहिए कि "a" स्ट्रिंग कैसे है, बुलियन नहीं। इस बारे में अच्छी बात यह है कि यह स्वतः स्वचालित परीक्षण ढांचे में चलाया जा सकता है साथ ही, यदि आप उन्हें प्रदान करते हैं और कुछ भी गलत है, तो PyCharm आपके कोड के प्रकारों को जांचेंगे।





static-code-analysis