Jak generować dynamiczne (parametryzowane) testy jednostkowe w Pythonie?

Mam jakieś dane testowe i chcę utworzyć test jednostkowy dla każdego elementu. Moim pierwszym pomysłem było zrobienie tego w ten sposób:

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()

Minusem tego jest to, że obsługuje wszystkie dane w jednym teście. Chciałbym wygenerować jeden test dla każdego przedmiotu w locie. Jakieś sugestie?

Author: Community, 2008-08-28

22 answers

Używam czegoś takiego:

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()

The parameterized pakiet może być użyty do automatyzacji tego procesu:

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)

Które wygenerują testy:

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'
 122
Author: Dmitry Mukhin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-29 00:36:54

Korzystanie z unittest (od 3.4)

Od wersji Pythona 3.4 pakiet biblioteki standardowej unittest posiada menedżera kontekstu subTest.

Zobacz dokumentację:

Przykład:

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)

Możesz również określić niestandardowe wartości wiadomości i parametrów na subTest():

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

Używanie nosa

The nos {[18] } wspiera to .

Przykład (poniższy kod to cała zawartość pliku zawierającego test):

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

Wyjście komendy 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)
 84
Author: codeape,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-25 12:23:33

Można to rozwiązać elegancko za pomocą Metaklasy:

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()
 58
Author: Guy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-25 19:11:59

Począwszy od Pythona 3.4 subtesty zostały wprowadzone do unittest w tym celu. Szczegóły można znaleźć w dokumentacji. TestCase.subTest jest menedżerem kontekstu, który pozwala wyizolować twierdzenia w teście tak, że awaria zostanie zgłoszona z informacjami o parametrach, ale nie zatrzymuje wykonania testu. Oto przykład z dokumentacji:

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)

Wynik testu będzie:

======================================================================
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

Jest to również część unittest2 , więc jest dostępna dla wcześniejszych wersje Pythona.

 40
Author: Bernhard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-28 04:48:22

Load_tests jest mało znanym mechanizmem wprowadzonym w 2.7 do dynamicznego tworzenia TestSuite. Dzięki niemu możesz łatwo tworzyć sparametryzowane testy.

Na przykład:

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

Ten kod uruchomi wszystkie testy w TestSuite zwracane przez load_tests. Żadne inne testy nie są uruchamiane automatycznie przez mechanizm discovery.

Alternatywnie możesz również użyć dziedziczenia, jak pokazano w tym paragonie: http://bugs.python.org/msg151444

 30
Author: Javier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-24 01:55:47

Można to zrobić za pomocą pytest . Wystarczy zapisać plik test_me.py z zawartością:

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

I uruchom test za pomocą polecenia py.test --tb=short test_me.py. Wtedy wynik będzie wyglądał następująco:

=========================== 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 ====================
To proste!. Również posiada więcej funkcji takich jak fixtures, mark, assert, itd ...
 26
Author: Sergey Voronezhskiy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-02 15:08:01

Użyj biblioteki ddt . Dodaje proste dekoratory dla metod testowych:

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))

Tę bibliotekę można zainstalować za pomocą pip. Nie wymaga nose i doskonale współpracuje z modułem standardowej biblioteki unittest.

 8
Author: Mykhaylo Kopytonenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-21 05:13:11

Możesz skorzystać z biblioteki TestScenarios .

Testscenarios zapewnia czysty zastrzyk zależności dla testów unitest style Pythona. Może to być użyte do testowania interfejsu (testowanie wielu implementacji za pomocą jednego zestawu testów) lub do klasycznego wtrysku zależności (dostarczać testy z zależnościami zewnętrznie do samego kodu testowego, umożliwiając łatwe testowanie w różnych sytuacjach).

 6
Author: bignose,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-01 03:59:06

Możesz użyć nose-ittr plugin (pip install nose-ittr).

Jest bardzo łatwy do integracji z istniejącymi testami, wymagane są minimalne zmiany (jeśli istnieją). Obsługuje również wtyczkę nose multiprocessing.

Nie to, że możesz mieć również funkcję customize setup na test.

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

Możliwe jest również przekazanie nosetest parametrów, jak za pomocą wbudowanej wtyczki attrib, w ten sposób można uruchomić tylko określony test z określonym parametrem:

nosetest -a number=2
 4
Author: Maroun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-02 13:39:03

Istnieje również hipoteza, która dodaje fuzz lub testowanie oparte na właściwościach: https://pypi.python.org/pypi/hypothesis

Jest to bardzo potężna metoda testowania.

 4
Author: Javier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-24 02:00:00

Natknąłem sięParamUnittest innego dnia, gdy patrzymy na kod źródłowy Radona (przykładowe użycie na github repo ). Powinien współpracować z innymi frameworkami, które rozszerzają TestCase (np. Nose).

Oto przykład:

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
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-06 01:21:50

Używam metaklasów i dekoratorów do generowania testów. Możesz sprawdzić moją implementację python_wrap_cases . Ta biblioteka nie wymaga żadnych frameworków testowych.

Twój przykład:

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)

Wyjście konsoli:

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
Możesz również użyć generatorów . Na przykład ten kod generuje wszystkie możliwe kombinacje testów z argumentami a__list i 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)

Wyjście konsoli:

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
Author: Kirill Ermolov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-21 10:13:54

Po prostu użyj metaklasy, jak widać tutaj;

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

Wyjście:

test_sample (ExampleTestCase) ... OK
 1
Author: sleepycal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-10 11:43:23
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)

Wynik:

>>> 
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
Author: Arindam Roychowdhury,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-07 06:10:16

Możesz używać klas TestSuite i niestandardowych klas 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)
 1
Author: Max Malysh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-08 18:32:19

Miałem problemy z bardzo specyficznym stylem parametryzowanych testów. Wszystkie nasze testy Selenium mogą być uruchamiane lokalnie, ale powinny być również uruchamiane zdalnie na kilku platformach w SauceLabs. Zasadniczo chciałem wziąć dużą ilość już napisanych przypadków testowych i sparametryzować je z jak najmniejszą ilością zmian w kodzie. Co więcej, musiałem być w stanie przekazać parametry do metody konfiguracji, coś, co nie widziałem żadnych rozwiązań dla gdzie indziej.

Oto co wymyśliłem:

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

Z tym, wszystko co musiałem zrobić, to dodać prosty dekorator @sauce_labs() do każdej zwykłej starej Skrzynki testowej, a teraz, gdy je uruchamiam, są one zawijane i przepisywane, tak że wszystkie metody testowe są parametryzowane i zmieniane. LoginTests.test_login (self) uruchamia się jako LoginTests.test_login_internet_explorer_10.0 (self), LoginTests.test_login_internet_explorer_11.0 (self) i LoginTests.test_login_firefox_43.0 (self), a każdy z nich ma parametr self.platforma do decydowania, z jaką przeglądarką / platformą uruchomić, nawet w Logintestach.konfiguracja, która jest kluczowa dla mojego zadania, ponieważ tam inicjowane jest połączenie z SauceLabs.

W każdym razie, mam nadzieję, że może to być pomocne dla kogoś, kto chce wykonać podobną" globalną " parametryzację swoich testów!

 0
Author: Danielle Weisz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-22 08:02:46

To rozwiązanie działa z unittest i nose:

#!/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()
 0
Author: mop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-06 13:57:36

Odpowiedzi oparte na metaclass nadal działają w Python3, ale zamiast atrybutu __metaclass__ należy użyć parametru metaclass, jak w:

class ExampleTestCase(TestCase,metaclass=DocTestMeta):
    pass
 0
Author: Patrick Ohly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-08 15:25:51

Meta-programowanie jest zabawne, ale może być w drodze. Większość rozwiązań tutaj utrudnia:

  • wybiórczo uruchom test
  • wskaż kod podany w nazwie testu
Tak więc, moją pierwszą sugestią jest podążanie prostą / wyraźną ścieżką (działa z dowolnym biegaczem testowym):]}
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()

Ponieważ nie powinniśmy się powtarzać, moja druga sugestia opiera się na odpowiedzi @ Javiera: embrace property based testing. Biblioteka hipotez:

  • jest " bardziej nieubłaganie przebiegły o pokoleniu przypadków testowych niż my, zwykli ludzie " [9]}
  • dostarczy proste przykłady liczenia
  • działa z każdym biegaczem testowym
  • Posiada wiele innych ciekawych funkcji (statystyki, dodatkowe wyniki testów, ...)

    Class TestSequence (unittest.TestCase): {]}

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

Aby przetestować konkretne przykłady, wystarczy dodać:

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

Aby uruchomić tylko jeden konkretny przykład, możesz skomentować Pozostałe przykłady(podany przykład zostanie uruchomiony jako pierwszy). Możesz chcieć aby użyć @given(st.nothing()). Inną opcją jest zastąpienie całego bloku przez:

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

Ok, nie masz odrębnych nazw testów. Ale może po prostu potrzebujesz:

  • opisowa nazwa testowanej nieruchomości.
  • które wejście prowadzi do niepowodzenia(przykład fałszujący).

Śmieszniejszy przykład

 0
Author: YvesgereY,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-08 13:59:37

Bardzo późno na imprezę, ale miałem problem z wykonaniem tego dla setUpClass.

Oto wersja @ Javier ' s answer , która daje setUpClass dostęp do dynamicznie przydzielanych atrybutów.

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

Wyjścia

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

OK
 0
Author: hhquark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-25 21:24:22

Oprócz używania setattr, możemy używać load_tests od Pythona 3.2. Proszę zapoznać się z wpisem na blogu blog.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
Author: pptime,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-26 22:29:51

Oto moje rozwiązanie. Uważam to za przydatne, gdy: 1. Powinien pracować dla unittest.Testcase i unittest discover 2. Mieć zestaw testów do uruchomienia dla różnych ustawień parametrów. 3. Bardzo proste brak zależności od innych pakietów import unittest

    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
Author: S.Arora,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-02 16:35:17