आप अजगर में गतिशील (पैरामीटरकृत) इकाई परीक्षण कैसे उत्पन्न करते हैं?


234

मेरे पास कुछ प्रकार के परीक्षण डेटा हैं और प्रत्येक आइटम के लिए एक इकाई परीक्षण बनाना चाहते हैं। मेरा पहला विचार इसे इस तरह करना था:

import unittest

l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]

class TestSequence(unittest.TestCase):
    def testsample(self):
        for name, a,b in l:
            print "test", name
            self.assertEqual(a,b)

if __name__ == '__main__':
    unittest.main()

इसका नकारात्मक पक्ष यह है कि यह एक परीक्षण में सभी डेटा को संभालता है। मैं मक्खी पर प्रत्येक आइटम के लिए एक परीक्षण उत्पन्न करना चाहूंगा। कोई सुझाव?



2
एक अच्छा लिंक है जो एक उत्तर प्रदान कर सकता है: eli.thegreenplace.net/2014/04/02/…
gaborous

जवाबों:


173

इसे "पैरामीरीज़ेशन" कहा जाता है।

कई उपकरण हैं जो इस दृष्टिकोण का समर्थन करते हैं। उदाहरण के लिए:

परिणामी कोड इस तरह दिखता है:

from parameterized import parameterized

class TestSequence(unittest.TestCase):
    @parameterized.expand([
        ["foo", "a", "a",],
        ["bar", "a", "b"],
        ["lee", "b", "b"],
    ])
    def test_sequence(self, name, a, b):
        self.assertEqual(a,b)

जो परीक्षण उत्पन्न करेंगे:

test_sequence_0_foo (__main__.TestSequence) ... ok
test_sequence_1_bar (__main__.TestSequence) ... FAIL
test_sequence_2_lee (__main__.TestSequence) ... ok

======================================================================
FAIL: test_sequence_1_bar (__main__.TestSequence)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/parameterized/parameterized.py", line 233, in <lambda>
    standalone_func = lambda *a: func(*(a + p.args), **p.kwargs)
  File "x.py", line 12, in test_sequence
    self.assertEqual(a,b)
AssertionError: 'a' != 'b'

ऐतिहासिक कारणों से मैं मूल उत्तर 2008 छोड़ दूंगा):

मैं कुछ इस तरह का उपयोग करें:

import unittest

l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]

class TestSequense(unittest.TestCase):
    pass

def test_generator(a, b):
    def test(self):
        self.assertEqual(a,b)
    return test

if __name__ == '__main__':
    for t in l:
        test_name = 'test_%s' % t[0]
        test = test_generator(t[1], t[2])
        setattr(TestSequense, test_name, test)
    unittest.main()

24
दरअसल, bignose, यह कोड प्रत्येक परीक्षण के लिए एक अलग नाम उत्पन्न करता है (यह वास्तव में अन्यथा काम नहीं करेगा)। उदाहरण में दिए गए परीक्षणों को क्रमशः "test_foo", "test_bar" और "test_lee" नाम दिया जाएगा। इस प्रकार आपके द्वारा उल्लेखित लाभ (और यह एक बड़ा है) तब तक संरक्षित किया जाता है जब तक आप समझदार नाम उत्पन्न करते हैं।
तोजी

1
जैसा कि @codeape द्वारा दिया गया उत्तर बताता है, नाक इसे संभालती है। हालांकि, यूनिकोड को संभालने में नाक नहीं लगती है; इसलिए मेरे लिए यह एक बेहतर समाधान है। +1
कीथ पिंसन

5
तो ध्यान दें, डुप्लिकेट प्रश्न में अधिक उचित उत्तर दिया गया है : stackoverflow.com/a/2799009/322020 - आपके पास परीक्षण .__name__ =सक्षम करने के लिए उपयोग है.exact_method
Nakilon

7
if __name__ == '__main__'सशर्त में कक्षा को संशोधित करने वाला कोड क्यों दिखाई देता है ? निश्चित रूप से इसे आयात समय पर चलाने के लिए इसके बाहर जाना चाहिए (यह याद करते हुए कि अजगर मॉड्यूल केवल एक बार आयात किए जाते हैं भले ही कई अलग-अलग स्थानों से आयात किए गए हों)
SpoonMeiser

4
मुझे नहीं लगता कि यह एक अच्छा समाधान है। यूनीटेस्ट का कोड उस तरीके पर निर्भर नहीं होना चाहिए, जिस पर उसे बुलाया जाता है। TestCase नाक या pytest या एक अलग परीक्षण वातावरण में प्रयोग करने योग्य होना चाहिए।
गुफ्तगू

146

(3.4 के बाद से) का उपयोग करना

पायथन 3.4 के बाद से, मानक पुस्तकालय unittestपैकेज में subTestसंदर्भ प्रबंधक है।

प्रलेखन देखें:

उदाहरण:

from unittest import TestCase

param_list = [('a', 'a'), ('a', 'b'), ('b', 'b')]

class TestDemonstrateSubtest(TestCase):
    def test_works_as_expected(self):
        for p1, p2 in param_list:
            with self.subTest():
                self.assertEqual(p1, p2)

आप एक कस्टम संदेश और पैरामीटर मान भी निर्दिष्ट कर सकते हैं subTest():

with self.subTest(msg="Checking if p1 equals p2", p1=p1, p2=p2):

नाक का उपयोग करना

नाक परीक्षण ढांचे इस का समर्थन करता है

उदाहरण (नीचे दिया गया कोड परीक्षण युक्त फ़ाइल की संपूर्ण सामग्री है):

param_list = [('a', 'a'), ('a', 'b'), ('b', 'b')]

def test_generator():
    for params in param_list:
        yield check_em, params[0], params[1]

def check_em(a, b):
    assert a == b

Nosetests कमांड का आउटपुट:

> nosetests -v
testgen.test_generator('a', 'a') ... ok
testgen.test_generator('a', 'b') ... FAIL
testgen.test_generator('b', 'b') ... ok

======================================================================
FAIL: testgen.test_generator('a', 'b')
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.5/site-packages/nose-0.10.1-py2.5.egg/nose/case.py", line 203, in runTest
    self.test(*self.arg)
  File "testgen.py", line 7, in check_em
    assert a == b
AssertionError

----------------------------------------------------------------------
Ran 3 tests in 0.006s

FAILED (failures=1)

3
यह डायनामिक रूप से परीक्षण मामलों को उत्पन्न करने का एक बहुत साफ तरीका है।
जाबोर

लेकिन ध्यान रहे, 'सेटअप ()' को यह पता नहीं होगा कि पैदावार के लिए तर्कों के रूप में किस चर का उपयोग किया जा रहा है। वास्तव में सेटअप () पता नहीं चलेगा कि क्या परीक्षण चल रहा है, या test_generator () के अंदर सेट किए गए vars। यह सेटअप () के भीतर विवेक की जाँच को जटिल बनाता है, और यह एक कारण है कि कुछ लोग py.test को पसंद करते हैं।
स्कॉट प्रिव

1
अद्यतन अनुभाग के लिए अपग्रेड किया गया। बिल्कुल वही जो मुझे चाहिए था। :)
सौरभ श्रीवास्तव

1
क्या पाइटेस्ट के साथ यूनीटेस्ट संस्करण को चलाने का एक तरीका है, ताकि यह सभी मामलों को चलाए और पहले असफल पैरामीटर पर न रुके?
kakk11

1
जैसा कि @ kakk11 द्वारा बताया गया है, यह उत्तर (और सामान्य तौर पर सबटेस्ट) पाइस्टेस्ट के साथ काम नहीं करता है। यह एक जाना - माना मुद्दा है। इस काम को करने के लिए एक सक्रिय रूप से विकसित प्लगइन है: github.com/pytest-dev/pytest-subtests
Jérémie

76

इसे मेटाक्लासेस का उपयोग करके सुरुचिपूर्ण ढंग से हल किया जा सकता है:

import unittest

l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]

class TestSequenceMeta(type):
    def __new__(mcs, name, bases, dict):

        def gen_test(a, b):
            def test(self):
                self.assertEqual(a, b)
            return test

        for tname, a, b in l:
            test_name = "test_%s" % tname
            dict[test_name] = gen_test(a,b)
        return type.__new__(mcs, name, bases, dict)

class TestSequence(unittest.TestCase):
    __metaclass__ = TestSequenceMeta

if __name__ == '__main__':
    unittest.main()

1
इसने मेरे लिए सेलेनियम के साथ महान काम किया। एक नोट के रूप में, क्लास टेस्टस्पेंसेंस में, आप "स्थिर" विधियों को सेटअप (स्वयं), is_element_pret (स्वयं, कैसे, क्या), ... आंसू (स्व) जैसे परिभाषित कर सकते हैं। उन्हें "के बाद लाना metaclass = TestSequenceMeta" बयान काम करने लगता है।
प्यार और शांति -

5
यह समाधान स्वीकृत IMHO के रूप में चयनित एक से बेहतर है।
पेट्रोस्लाम्ब

2
@petroslamb मेटाक्लास में __new__विधि को तब बुलाया जाता है जब वर्ग स्वयं को परिभाषित करता है, न कि जब पहला उदाहरण बनाया जाता है। मुझे लगता है कि गतिशील रूप से परीक्षण विधियों के इस तरीके का उपयोग इस बात के unittestनिर्धारण के लिए उपयोग किए जाने वाले आत्मनिरीक्षण के साथ अधिक संगत है कि एक कक्षा में कितने परीक्षण हैं (अर्थात यह उस वर्ग का उदाहरण बनाने से पहले परीक्षणों की सूची संकलित कर सकता है)।
बिलीबोन

11
नोट: अजगर 3 में, इसे इसमें बदल दें:class TestSequence(unittest.TestCase, metaclass=TestSequenceMeta):[...]
मैथ्यू_ड्यू

3
क्या आप dctइसके बजाय उपयोग कर सकते हैं dict? चर नाम के रूप में कीवर्ड का उपयोग करना भ्रमित और त्रुटि-प्रवण है।
npfoss

49

पायथन 3.4 के रूप में इस प्रयोजन के लिए यूनिटीस्ट को सबटाइटल पेश किया गया है। देखें प्रलेखन जानकारी के लिए। TestCase.subTest एक संदर्भ प्रबंधक है जो किसी को परीक्षण में जोर लगाने के लिए अनुमति देता है ताकि पैरामीटर जानकारी के साथ विफलता की सूचना दी जाएगी लेकिन परीक्षण निष्पादन को रोक नहीं सकता है। यहाँ प्रलेखन से उदाहरण है:

class NumbersTest(unittest.TestCase):

def test_even(self):
    """
    Test that numbers between 0 and 5 are all even.
    """
    for i in range(0, 6):
        with self.subTest(i=i):
            self.assertEqual(i % 2, 0)

टेस्ट रन का आउटपुट होगा:

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=1)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "subtests.py", line 32, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=3)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "subtests.py", line 32, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=5)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "subtests.py", line 32, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

यह भी unittest2 का हिस्सा है , इसलिए यह पायथन के पुराने संस्करणों के लिए उपलब्ध है।


1
सबसे अच्छा समाधान यदि आप 3.4 और उच्चतर अजगर का उपयोग करते हैं।
मैक्स मलिश

4
Unittest2 का उपयोग करते हुए, यह पायथन 2.7 के लिए भी उपलब्ध है।
बर्नहार्ड

11
इस दृष्टिकोण और अलग-अलग परीक्षणों के बीच एक बड़ा अंतर यह है कि परीक्षण की स्थिति हर बार रीसेट नहीं होती है। (यह है, setUp()और tearDown()उप-परीक्षणों के बीच नहीं चलाया जाता है।)
केविन क्रिस्टोफर हेनरी

1
@KevinChristopherHenry हाँ, लेकिन self.setUp()सिद्धांत रूप में सूक्ष्म रूप से भीतर से बुलाया जा सकता है। के रूप में tearDown, यह अंत में स्वचालित रूप से कहा जाता है पर्याप्त हो सकता है।
एक्यूमेनस

मुझे लगता है कि यह शक्तिशाली हो सकता है जब ऊपर दिए गए मेटाक्लस दृष्टिकोण के साथ संयोजन में उपयोग किया जाता है।
नाथन चैपल

36

load_tests 2.7 में पेश किया गया एक छोटा सा ज्ञात तंत्र है जो गतिशील रूप से TestSuite बनाता है। इसके साथ, आप आसानी से पैराट्राइज्ड परीक्षण बना सकते हैं।

उदाहरण के लिए:

import unittest

class GeneralTestCase(unittest.TestCase):
    def __init__(self, methodName, param1=None, param2=None):
        super(GeneralTestCase, self).__init__(methodName)

        self.param1 = param1
        self.param2 = param2

    def runTest(self):
        pass  # Test that depends on param 1 and 2.


def load_tests(loader, tests, pattern):
    test_cases = unittest.TestSuite()
    for p1, p2 in [(1, 2), (3, 4)]:
        test_cases.addTest(GeneralTestCase('runTest', p1, p2))
    return test_cases

वह कोड सभी TestCases को TestSuite में load_tests द्वारा वापस चलाएगा। कोई अन्य परीक्षण स्वचालित रूप से खोज तंत्र द्वारा नहीं चलाया जाता है।

वैकल्पिक रूप से, आप इस टिकट में दिखाए गए अनुसार इनहेरिटेंस का भी उपयोग कर सकते हैं: http://bugs.python.org/msg151444


1
उपरोक्त कोड विफल रहता है: TypeError: __init __ () सबसे अधिक 2 तर्क (4 दिए गए) लेता है
अधिकतम

2
कंस्ट्रक्टर अतिरिक्त मापदंडों के लिए अशक्त चूक को जोड़ा गया।
जेवियर

मैं @ मोजो के उत्तर में नाक-पैरामीटर कोड पसंद करता हूं , लेकिन मेरे ग्राहकों के लिए यह एक अतिरिक्त निर्भरता से बचने के लिए बहुत उपयोगी है इसलिए मैं उनके लिए इसका उपयोग करूंगा।
ऋषि

1
यह समाधान इस पेज पर मेरा पसंदीदा था। मौजूदा शीर्ष उत्तर में सुझाए गए दोनों नाक , और इसके कांटे Nose2 केवल रखरखाव हैं, और बाद वाले सुझाव देते हैं कि उपयोगकर्ता इसके बजाय pytest का प्रयास करते हैं । क्या गड़बड़ है - मैं इस तरह से एक देशी दृष्टिकोण से चिपकेगा!
सीन

1
बोनस: उत्पादन के लिए लघुकरण विधि को फिर से परिभाषित करने की क्षमता पारस में पारित
fun_vit

33

यह पाइस्टेस्ट का उपयोग करके किया जा सकता है । बस test_me.pyसामग्री के साथ फाइल लिखें :

import pytest

@pytest.mark.parametrize('name, left, right', [['foo', 'a', 'a'],
                                               ['bar', 'a', 'b'],
                                               ['baz', 'b', 'b']])
def test_me(name, left, right):
    assert left == right, name

और कमांड के साथ अपना टेस्ट चलाएं py.test --tb=short test_me.py। तब आउटपुट जैसा दिखेगा:

=========================== test session starts ============================
platform darwin -- Python 2.7.6 -- py-1.4.23 -- pytest-2.6.1
collected 3 items

test_me.py .F.

================================= FAILURES =================================
_____________________________ test_me[bar-a-b] _____________________________
test_me.py:8: in test_me
    assert left == right, name
E   AssertionError: bar
==================== 1 failed, 2 passed in 0.01 seconds ====================

यह सरल!। इसके अलावा pytest की तरह अधिक सुविधाएं हैं fixtures, mark, assert, आदि ...


1
मैं एक सरल, सीधे आगे उदाहरण के लिए देख रहा था कि कैसे py.test के साथ पैरामीरीज़ परीक्षण के मामले हैं। आपका बहुत बहुत धन्यवाद!
टाइमगैब

@timgeb मुझे आपकी मदद करने में खुशी हो रही है। अधिक उदाहरणों के लिए py.test टैग देखें । इसके अलावा मैं मानव पठनीय mutchers, जो संशोधित किया जा सकता है, संयुक्त या अपने तरीके से बनाया के साथ कुछ चीनी जोड़ने के लिए हैमस्ट्रेट का उपयोग करने का सुझाव है । इसके अलावा हमारे पास एल्यूर-पायथन है , एक अच्छी दिखने वाली रिपोर्ट जनरेशन के लिएpy.test
सर्गेई

धन्यवाद। मैं बस unittestpy.test से आगे बढ़ना शुरू कर दिया । मेरे पास TestCaseआधार कक्षाएं थीं जो अलग-अलग तर्कों के साथ बच्चों को गतिशील रूप से बनाने में सक्षम थीं, जिन्हें वे कक्षा चर के रूप में संग्रहीत करते थे ... जो थोड़ा सा अस्पष्ट था।
टाइमजैब

1
@timgeb हां आप सही हैं। सबसे हत्यारा सुविधा की py.testहै yield_fixtures । जो सेटअप कर सकता है , परीक्षण में कुछ उपयोगी डेटा लौटा सकता है और परीक्षण समाप्त होने के बाद फाड़ सकता है । जुड़नार भी पैरामीरीकृत हो सकते हैं ।
सेर्गेई वोरोनेज़स्की

12

Ddt लाइब्रेरी का उपयोग करें । यह परीक्षण विधियों के लिए सरल सज्जाकार जोड़ता है:

import unittest
from ddt import ddt, data
from mycode import larger_than_two

@ddt
class FooTestCase(unittest.TestCase):

    @data(3, 4, 12, 23)
    def test_larger_than_two(self, value):
        self.assertTrue(larger_than_two(value))

    @data(1, -3, 2, 0)
    def test_not_larger_than_two(self, value):
        self.assertFalse(larger_than_two(value))

इस पुस्तकालय के साथ स्थापित किया जा सकता है pip। इसकी आवश्यकता नहीं है nose, और मानक पुस्तकालय unittestमॉड्यूल के साथ उत्कृष्ट काम करता है ।


6

आपको TestScenarios लाइब्रेरी की कोशिश करने से लाभ होगा ।

testcenarios python unittest शैली परीक्षणों के लिए स्वच्छ निर्भरता इंजेक्शन प्रदान करता है। इसका उपयोग इंटरफ़ेस परीक्षण (एकल परीक्षण सूट के माध्यम से कई कार्यान्वयन का परीक्षण) या क्लासिक निर्भरता इंजेक्शन के लिए किया जा सकता है (परीक्षण कोड में ही निर्भरता के साथ परीक्षण प्रदान करें, विभिन्न स्थितियों में आसान परीक्षण की अनुमति देता है)।


5

हाइपोथीसिस भी है जो फ़ज़ या संपत्ति आधारित परीक्षण जोड़ता है: https://pypi.python.org/pypi/hypothesis

यह एक बहुत शक्तिशाली परीक्षण विधि है।


मैं @given()unittest वर्ग के अंदर मैक्रो का उपयोग नहीं कर सका ।
जॉन ग्रीन


4

आप nose-ittr plugin ( pip install nose-ittr) का उपयोग कर सकते हैं ।

मौजूदा परीक्षणों के साथ एकीकृत करना बहुत आसान है, न्यूनतम परिवर्तन (यदि कोई हो) की आवश्यकता है। यह नाक के मल्टीप्रोसेसिंग प्लगइन का भी समर्थन करता है ।

ऐसा नहीं है कि आप setupप्रति परीक्षण अनुकूलित कार्य भी कर सकते हैं ।

@ittr(number=[1, 2, 3, 4])   
def test_even(self):   
    assert_equal(self.number % 2, 0)

nosetestउनके बिल्ड-इन प्लगइन के साथ मापदंडों को पास करना भी संभव है attrib, इस तरह आप केवल विशिष्ट पैरामीटर के साथ एक विशिष्ट परीक्षण चला सकते हैं:

nosetest -a number=2

मुझे यह दृष्टिकोण पसंद है, विशेष रूप से प्रति विधि स्तर यह समर्थन करता है।
मैट

3

मैं परीक्षण उत्पन्न करने के लिए मेटाक्लस और डेकोरेटर का उपयोग करता हूं। आप मेरे कार्यान्वयन python_wrap_cases की जांच कर सकते हैं । इस लाइब्रेरी को किसी भी परीक्षण ढांचे की आवश्यकता नहीं है।

आपका उदाहरण:

import unittest
from python_wrap_cases import wrap_case


@wrap_case
class TestSequence(unittest.TestCase):

    @wrap_case("foo", "a", "a")
    @wrap_case("bar", "a", "b")
    @wrap_case("lee", "b", "b")
    def testsample(self, name, a, b):
        print "test", name
        self.assertEqual(a, b)

कंसोल आउटपुट:

testsample_u'bar'_u'a'_u'b' (tests.example.test_stackoverflow.TestSequence) ... test bar
FAIL
testsample_u'foo'_u'a'_u'a' (tests.example.test_stackoverflow.TestSequence) ... test foo
ok
testsample_u'lee'_u'b'_u'b' (tests.example.test_stackoverflow.TestSequence) ... test lee
ok

इसके अलावा आप जनरेटर का उपयोग कर सकते हैं । उदाहरण के लिए यह कोड तर्कों के साथ परीक्षणों के सभी संभावित संयोजनों को उत्पन्न करता है a__listऔरb__list

import unittest
from python_wrap_cases import wrap_case


@wrap_case
class TestSequence(unittest.TestCase):

    @wrap_case(a__list=["a", "b"], b__list=["a", "b"])
    def testsample(self, a, b):
        self.assertEqual(a, b)

कंसोल आउटपुट:

testsample_a(u'a')_b(u'a') (tests.example.test_stackoverflow.TestSequence) ... ok
testsample_a(u'a')_b(u'b') (tests.example.test_stackoverflow.TestSequence) ... FAIL
testsample_a(u'b')_b(u'a') (tests.example.test_stackoverflow.TestSequence) ... FAIL
testsample_a(u'b')_b(u'b') (tests.example.test_stackoverflow.TestSequence) ... ok

2

मैं दूसरे दिन पारामुनीटेस्ट में आया था जब राडोण के स्रोत कोड को देख रहा था ( उदाहरण गीथब रेपो पर उपयोग )। इसे अन्य रूपरेखाओं के साथ काम करना चाहिए जो टेस्टकेस (जैसे नाक) का विस्तार करते हैं।

यहाँ एक उदाहरण है:

import unittest
import paramunittest


@paramunittest.parametrized(
    ('1', '2'),
    #(4, 3),    <---- uncomment to have a failing test
    ('2', '3'),
    (('4', ), {'b': '5'}),
    ((), {'a': 5, 'b': 6}),
    {'a': 5, 'b': 6},
)
class TestBar(TestCase):
    def setParameters(self, a, b):
        self.a = a
        self.b = b

    def testLess(self):
        self.assertLess(self.a, self.b)

2
import unittest

def generator(test_class, a, b):
    def test(self):
        self.assertEqual(a, b)
    return test

def add_test_methods(test_class):
    #First element of list is variable "a", then variable "b", then name of test case that will be used as suffix.
    test_list = [[2,3, 'one'], [5,5, 'two'], [0,0, 'three']]
    for case in test_list:
        test = generator(test_class, case[0], case[1])
        setattr(test_class, "test_%s" % case[2], test)


class TestAuto(unittest.TestCase):
    def setUp(self):
        print 'Setup'
        pass

    def tearDown(self):
        print 'TearDown'
        pass

_add_test_methods(TestAuto)  # It's better to start with underscore so it is not detected as a test itself

if __name__ == '__main__':
    unittest.main(verbosity=1)

परिणाम:

>>> 
Setup
FTearDown
Setup
TearDown
.Setup
TearDown
.
======================================================================
FAIL: test_one (__main__.TestAuto)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:/inchowar/Desktop/PyTrash/test_auto_3.py", line 5, in test
    self.assertEqual(a, b)
AssertionError: 2 != 3

----------------------------------------------------------------------
Ran 3 tests in 0.019s

FAILED (failures=1)

1
अपने def add_test_methodsकार्य के साथ मामूली समस्या । क्या def _add_test_methods मुझे सोचना चाहिए
Raychaser

@ रायाचैजर ... आप सही हैं..मैंने तय किया लेकिन इसे यहां अपडेट नहीं किया .... इसे पकड़ने के लिए धन्यवाद।
अरिंदम रॉयचौधरी

1

बस मेटाक्लस का उपयोग करें, जैसा कि यहां देखा गया है;

class DocTestMeta(type):
    """
    Test functions are generated in metaclass due to the way some
    test loaders work. For example, setupClass() won't get called
    unless there are other existing test methods, and will also
    prevent unit test loader logic being called before the test
    methods have been defined.
    """
    def __init__(self, name, bases, attrs):
        super(DocTestMeta, self).__init__(name, bases, attrs)

    def __new__(cls, name, bases, attrs):
        def func(self):
            """Inner test method goes here"""
            self.assertTrue(1)

        func.__name__ = 'test_sample'
        attrs[func.__name__] = func
        return super(DocTestMeta, cls).__new__(cls, name, bases, attrs)

class ExampleTestCase(TestCase):
    """Our example test case, with no methods defined"""
    __metaclass__ = DocTestMeta

आउटपुट:

test_sample (ExampleTestCase) ... OK

1

आप उपयोग कर सकते हैं TestSuiteऔर कस्टम TestCaseकक्षाएं।

import unittest

class CustomTest(unittest.TestCase):
    def __init__(self, name, a, b):
        super().__init__()
        self.name = name
        self.a = a
        self.b = b

    def runTest(self):
        print("test", self.name)
        self.assertEqual(self.a, self.b)

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(CustomTest("Foo", 1337, 1337))
    suite.addTest(CustomTest("Bar", 0xDEAD, 0xC0DE))
    unittest.TextTestRunner().run(suite)

जबकि TestSuite काम करता है, तर्कों को __init__कार्य करने के लिए पारित नहीं किया जाता है ।
गुड़गांव

1

मैंने पाया है कि यह मेरे उद्देश्यों के लिए अच्छी तरह से काम करता है, खासकर अगर मुझे ऐसे परीक्षण उत्पन्न करने की आवश्यकता है जो डेटा के संग्रह पर थोड़ा अंतर प्रक्रियाएं करते हैं।

import unittest

def rename(newName):
    def renamingFunc(func):
        func.__name__ == newName
        return func
    return renamingFunc

class TestGenerator(unittest.TestCase):

    TEST_DATA = {}

    @classmethod
    def generateTests(cls):
        for dataName, dataValue in TestGenerator.TEST_DATA:
            for func in cls.getTests(dataName, dataValue):
                setattr(cls, "test_{:s}_{:s}".format(func.__name__, dataName), func)

    @classmethod
    def getTests(cls):
        raise(NotImplementedError("This must be implemented"))

class TestCluster(TestGenerator):

    TEST_CASES = []

    @staticmethod
    def getTests(dataName, dataValue):

        def makeTest(case):

            @rename("{:s}".format(case["name"]))
            def test(self):
                # Do things with self, case, data
                pass

            return test

        return [makeTest(c) for c in TestCluster.TEST_CASES]

TestCluster.generateTests()

TestGeneratorवर्ग की तरह परीक्षण मामलों के विभिन्न सेट अंडे देने के लिए इस्तेमाल किया जा सकता TestCluster

TestClusterTestGeneratorइंटरफ़ेस के कार्यान्वयन के रूप में सोचा जा सकता है।


1

यह समाधान के साथ काम करता unittestहै और noseअजगर 2 और अजगर 3 के लिए:

#!/usr/bin/env python
import unittest

def make_function(description, a, b):
    def ghost(self):
        self.assertEqual(a, b, description)
    print(description)
    ghost.__name__ = 'test_{0}'.format(description)
    return ghost


class TestsContainer(unittest.TestCase):
    pass

testsmap = {
    'foo': [1, 1],
    'bar': [1, 2],
    'baz': [5, 5]}

def generator():
    for name, params in testsmap.iteritems():
        test_func = make_function(name, params[0], params[1])
        setattr(TestsContainer, 'test_{0}'.format(name), test_func)

generator()

if __name__ == '__main__':
    unittest.main()

अपग्रेडेड वर्जन <3 के लिए @ guillaume-jacquenot धन्यवाद!
एमओपी

0

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

यहाँ मैं क्या लेकर आया हूँ:

import inspect
import types

test_platforms = [
    {'browserName': "internet explorer", 'platform': "Windows 7", 'version': "10.0"},
    {'browserName': "internet explorer", 'platform': "Windows 7", 'version': "11.0"},
    {'browserName': "firefox", 'platform': "Linux", 'version': "43.0"},
]


def sauce_labs():
    def wrapper(cls):
        return test_on_platforms(cls)
    return wrapper


def test_on_platforms(base_class):
    for name, function in inspect.getmembers(base_class, inspect.isfunction):
        if name.startswith('test_'):
            for platform in test_platforms:
                new_name = '_'.join(list([name, ''.join(platform['browserName'].title().split()), platform['version']]))
                new_function = types.FunctionType(function.__code__, function.__globals__, new_name,
                                                  function.__defaults__, function.__closure__)
                setattr(new_function, 'platform', platform)
                setattr(base_class, new_name, new_function)
            delattr(base_class, name)

    return base_class

इसके साथ, मुझे बस इतना करना था कि प्रत्येक नियमित पुराने टेस्टकैसे में एक साधारण डेकोरेटर @sauce_labs () जोड़ा जाए, और अब उन्हें चलाते समय, उन्हें लपेट कर फिर से लिखा जाता है, ताकि सभी परीक्षण विधियों को मानकीकृत और नाम बदला जा सके। LoginTests.test_login (सेल्फ) LoginTests.test_login_internet_explorer_10.0 (स्व), LoginTests.test_login_internet_explorer_11.0 (स्व), और LoginTests.test_login_firefox_43.0 (स्वयं), और प्रत्येक एक पैरामीटर और सेल्फी है। प्लेटफॉर्म के खिलाफ चलने के लिए, यहां तक ​​कि LoginTests.setUp में भी, जो कि मेरे कार्य के लिए महत्वपूर्ण है, जहां से SauceLabs का कनेक्शन प्रारंभिक है।

वैसे भी, मुझे उम्मीद है कि यह किसी ऐसे व्यक्ति की मदद हो सकती है जो अपने परीक्षणों के समान "वैश्विक" पैरामीटराइजेशन कर रहा है!


0

मेटाक्लास-आधारित उत्तर अभी भी पायथन 3 में काम करते हैं, लेकिन __metaclass__विशेषता के बजाय एक metaclassपैरामीटर का उपयोग करना पड़ता है , जैसे कि:

class ExampleTestCase(TestCase,metaclass=DocTestMeta):
    pass

0

मेटा-प्रोग्रामिंग मजेदार है, लेकिन रास्ते में मिल सकती है। यहां अधिकांश समाधान इसके लिए मुश्किल बनाते हैं:

  • चुनिंदा रूप से एक परीक्षण लॉन्च करें
  • कोड को परीक्षण के नाम पर वापस इंगित करें

इसलिए, मेरा पहला सुझाव सरल / स्पष्ट पथ का अनुसरण करना है (किसी भी परीक्षण धावक के साथ काम करता है):

import unittest

class TestSequence(unittest.TestCase):

    def _test_complex_property(self, a, b):
        self.assertEqual(a,b)

    def test_foo(self):
        self._test_complex_property("a", "a")
    def test_bar(self):
        self._test_complex_property("a", "b")
    def test_lee(self):
        self._test_complex_property("b", "b")

if __name__ == '__main__':
    unittest.main()

चूँकि हम खुद को दोहराना नहीं चाहते हैं, मेरा दूसरा सुझाव @ जेवियर के जवाब पर आधारित है: संपत्ति आधारित परीक्षण को गले लगाओ। परिकल्पना पुस्तकालय:

  • "हम मनुष्यों की तुलना में परीक्षण मामले की पीढ़ी के बारे में अधिक भरोसेमंद रूप से कुटिल"
  • सरल गिनती-उदाहरण प्रदान करेगा
  • किसी भी परीक्षण धावक के साथ काम करता है
  • कई और दिलचस्प विशेषताएं हैं (आंकड़े, अतिरिक्त परीक्षण आउटपुट, ...)

    वर्ग परीक्षण (unittest.TestCase):

    @given(st.text(), st.text())
    def test_complex_property(self, a, b):
        self.assertEqual(a,b)

अपने विशिष्ट उदाहरणों का परीक्षण करने के लिए, बस जोड़ें:

    @example("a", "a")
    @example("a", "b")
    @example("b", "b")

केवल एक विशेष उदाहरण को चलाने के लिए, आप अन्य उदाहरणों पर टिप्पणी कर सकते हैं (बशर्ते उदाहरण पहले चलाया जाएगा)। आप उपयोग करना चाह सकते हैं @given(st.nothing())। एक अन्य विकल्प यह है कि पूरे ब्लॉक को बदलकर:

    @given(st.just("a"), st.just("b"))

ठीक है, आपके पास अलग-अलग परीक्षण नाम नहीं हैं। लेकिन शायद आपको चाहिए:

  • परीक्षण के तहत संपत्ति का एक वर्णनात्मक नाम।
  • कौन सा इनपुट विफलता की ओर जाता है (उदाहरण गलत है)।

मजेदार उदाहरण


0

पार्टी के लिए सुपर लेट, लेकिन मुझे ये काम करने में परेशानी हुई setUpClass

यहाँ @ जेवियर के उत्तर का एक संस्करण है जो setUpClassगतिशील रूप से आवंटित विशेषताओं तक पहुँच देता है ।

import unittest


class GeneralTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print ''
        print cls.p1
        print cls.p2

    def runTest1(self):
        self.assertTrue((self.p2 - self.p1) == 1)

    def runTest2(self):
        self.assertFalse((self.p2 - self.p1) == 2)


def load_tests(loader, tests, pattern):
    test_cases = unittest.TestSuite()
    for p1, p2 in [(1, 2), (3, 4)]:
        clsname = 'TestCase_{}_{}'.format(p1, p2)
        dct = {
            'p1': p1,
            'p2': p2,
        }
        cls = type(clsname, (GeneralTestCase,), dct)
        test_cases.addTest(cls('runTest1'))
        test_cases.addTest(cls('runTest2'))
    return test_cases

आउटपुट

1
2
..
3
4
..
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

0

बस मिश्रण में एक और समाधान फेंकने के लिए;)

यह प्रभावी parameterizedरूप से ऊपर उल्लिखित के समान है, लेकिन इसके लिए विशिष्ट है unittest:

def sub_test(param_list):
    """Decorates a test case to run it as a set of subtests."""

    def decorator(f):

        @functools.wraps(f)
        def wrapped(self):
            for param in param_list:
                with self.subTest(**param):
                    f(self, **param)

        return wrapped

    return decorator

उदाहरण का उपयोग:

class TestStuff(unittest.TestCase):
    @sub_test([
        dict(arg1='a', arg2='b'),
        dict(arg1='x', arg2='y'),
    ])
    def test_stuff(self, a, b):
        ...

-1

सेटट्रा का उपयोग करने के अलावा, हम python 3.2 के बाद से load_tests का उपयोग कर सकते हैं। कृपया ब्लॉग पोस्ट ब्लॉग देखें। livreuro.com/en/coding/python/how-to-generate-discoverable-unit-tests-in-python-dynamically/

class Test(unittest.TestCase):
    pass

def _test(self, file_name):
    open(file_name, 'r') as f:
        self.assertEqual('test result',f.read())

def _generate_test(file_name):
    def test(self):
        _test(self, file_name)
    return test

def _generate_tests():
    for file in files:
        file_name = os.path.splitext(os.path.basename(file))[0]
        setattr(Test, 'test_%s' % file_name, _generate_test(file))

test_cases = (Test,)

def load_tests(loader, tests, pattern):
    _generate_tests()
    suite = TestSuite()
    for test_class in test_cases:
        tests = loader.loadTestsFromTestCase(test_class)
        suite.addTests(tests)
    return suite

if __name__ == '__main__':
    _generate_tests()
    unittest.main()

-1

निम्नलिखित मेरा समाधान है। मुझे यह तब उपयोगी लगता है जब: 1. यूनीटेस्ट के लिए काम करना चाहिए। टेस्टिकल और अनइस्टेस्ट डिस्कवर 2. विभिन्न पैरामीटर सेटिंग्स के लिए परीक्षण का एक सेट होना चाहिए। 3. बहुत सरल अन्य संकुल पर कोई निर्भरता unitest आयात करते हैं

    class BaseClass(unittest.TestCase):
        def setUp(self):
            self.param = 2
            self.base = 2

        def test_me(self):
            self.assertGreaterEqual(5, self.param+self.base)

        def test_me_too(self):
            self.assertLessEqual(3, self.param+self.base)



     class Child_One(BaseClass):
        def setUp(self):
            BaseClass.setUp(self)
            self.param = 4


     class Child_Two(BaseClass):
        def setUp(self):
            BaseClass.setUp(self)
            self.param = 1

यह उस सवाल का जवाब नहीं देता है, जो मक्खी पर परीक्षण पैदा करने के बारे में है।
०४

-1
import unittest

def generator(test_class, a, b,c,d,name):
    def test(self):
        print('Testexecution=',name)
        print('a=',a)
        print('b=',b)
        print('c=',c)
        print('d=',d)

    return test

def add_test_methods(test_class):
    test_list = [[3,3,5,6, 'one'], [5,5,8,9, 'two'], [0,0,5,6, 'three'],[0,0,2,3,'Four']]
    for case in test_list:
        print('case=',case[0], case[1],case[2],case[3],case[4])
        test = generator(test_class, case[0], case[1],case[2],case[3],case[4])
        setattr(test_class, "test_%s" % case[4], test)


class TestAuto(unittest.TestCase):
    def setUp(self):
        print ('Setup')
        pass

    def tearDown(self):
        print ('TearDown')
        pass

add_test_methods(TestAuto)

if __name__ == '__main__':
    unittest.main(verbosity=1)

ऐसा लगता है जैसे आपने वहां प्रारूपण खो दिया है। यह वास्तव में पढ़ने में कठिन है क्योंकि यह खड़ा है
आर्टुरो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.