Как сделать единичный тест, который сравнивает сгенерированный файл с ссылочным файлом в Python [duplicate]

Из документов Java 5 (Java 8 docs здесь ):

Когда объект MathContext поставляется с настройкой точности 0 (например, MathContext.UNLIMITED), арифметические операции точны, а также арифметические методы, которые не принимают объект MathContext. (Это единственное поведение, которое поддерживалось в версиях до 5.)

. В качестве следствия вычисления точного результата настройка режима округления объекта MathContext с точностью 0 не используется и таким образом, не имеет значения. В случае деления точное частное может иметь бесконечно длинное десятичное разложение; например, 1 делится на 3.

Если фактор имеет бесконечное десятичное расширение и операция указана для возврата точного результата, генерируется исключение ArithmeticException. В противном случае возвращается точный результат деления, как это сделано для других операций.

Чтобы исправить, вам нужно сделать что-то вроде этого:

a.divide(b, 2, RoundingMode.HALF_UP)

where 2 is precision and RoundingMode.HALF_UP is rounding mode

Подробнее подробности: http://jaydeepm.wordpress.com/2009/06/04/bigdecimal-and-non-terminating-decimal-expansion-error/

170
задан Community 1 March 2018 в 19:57
поделиться

22 ответа

Я использую что-то вроде этого:

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

Пакет nose-parameterized может использоваться для автоматизации этого процесса:

from nose_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/nose_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'
116
ответ дан David Wolever 16 August 2018 в 00:07
поделиться
  • 1
    На самом деле, bignose, этот код генерирует другое имя для каждого теста (он фактически не будет работать иначе). В приведенном примере выполненные тесты будут называться «test_foo», «test_bar» и «test_lee», соответственно. Таким образом, польза, которую вы упоминаете (и она большая), сохраняется до тех пор, пока вы генерируете разумные имена. – Toji 23 February 2011 в 17:52
  • 2
    Как говорит @codeape, нос справляется с этим. Однако нос, похоже, не обрабатывает Юникод; поэтому для меня это предпочтительное решение. +1 – Keith Pinson 13 August 2011 в 21:42
  • 3
    Обратите внимание, что более правильный ответ задается в вопросе duplicate : stackoverflow.com/a/2799009/322020 - вы используете .__name__ = для включения .exact_method тестирование – Nakilon 12 April 2013 в 11:38
  • 4
    Почему код, изменяющий класс, появляется в if __name__ == '__main__' условном? Разумеется, он должен выйти за пределы этого, чтобы работать во время импорта (помня, что модули python импортируются только один раз, даже если они импортированы из нескольких разных мест) – SpoonMeiser 21 December 2013 в 02:52
  • 5
    Я не думаю, что это хорошее решение. Код unittest не должен зависеть от способа его вызова. TestCase следует использовать в носу или в pytest или в другой тестовой среде. – guettli 29 April 2014 в 13:21

Используйте библиотеку 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.

8
ответ дан akaihola 16 August 2018 в 00:07
поделиться
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
ответ дан Arindam Roychowdhury 16 August 2018 в 00:07
поделиться
  • 1
    Незначительная проблема с вашей функцией def add_test_methods. Должно быть def _add_test_methods , я думаю – Raychaser 13 January 2017 в 20:12
  • 2
    @Raychaser ... Вы правы. Я исправил это, но не обновил его здесь ... Спасибо, что поймал это. – Arindam Roychowdhury 16 January 2017 в 11:45

Вам будет полезно попробовать библиотеку TestScenarios .

testscenarios обеспечивает чистую инъекцию зависимостей для тестов стиля стилей python. Это может быть использовано для тестирования интерфейса (тестирование многих реализаций через один набор тестов) или для классической инъекции зависимостей (обеспечить тестирование зависимостями внешне от самого тестового кода, что позволяет легко тестировать в разных ситуациях).

6
ответ дан bignose 16 August 2018 в 00:07
поделиться

Использование unittest (начиная с 3.4)

Поскольку Python 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)
78
ответ дан codeape 16 August 2018 в 00:07
поделиться
  • 1
    Это очень чистый способ динамического генерации тестовых примеров. – gaborous 29 July 2015 в 19:11
  • 2
    Лучший ответ. Такой короткий и такой чистый. – user1820801 23 October 2015 в 13:36
  • 3
    Но имейте в виду, что «setup ()» не будет знать, какие переменные используются в качестве аргументов. Фактически setup () не будет знать, какой тест запущен, или vars, установленный внутри test_generator (). Это усложняет проверку работоспособности в setup (), и это одна из причин, по которой некоторые люди предпочитают py.test. – Crossfit_and_Beer 29 January 2016 в 22:30
  • 4
    Это работает! но тогда вы не можете использовать unittest.TestCase и его семейства утвержденных * методов. – Shiplu Mokaddim 27 March 2018 в 13:15
  • 5
  • 6
    Активировано для раздела обновления. Именно то, что мне нужно. :) – Saurabh Shrivastava 25 June 2018 в 12:04

У меня возникли проблемы с особым стилем параметризованных тестов. Все наши тесты Selenium могут выполняться локально, но они также должны быть удалены удаленно на нескольких платформах на SauceLabs. В принципе, я хотел взять большое количество уже написанных тестовых примеров и параметризовать их с минимальными изменениями кода. Кроме того, мне нужно было передать параметры в метод setUp, то, что я не видел в других решениях.

Вот что я придумал:

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 () в каждый обычный старый TestCase, а теперь, когда его запускают, они завернуты и переписаны, так что все методы тестирования параметризуются и переименованы. LoginTests.test_login (self) работает как LoginTests.test_login_internet_explorer_10.0 (self), LoginTests.test_login_internet_explorer_11.0 (self) и LoginTests.test_login_firefox_43.0 (self), и каждый из них имеет параметр self.platform, чтобы решить, какой браузер / платформу для запуска, даже в LoginTests.setUp, что имеет решающее значение для моей задачи, поскольку именно там инициализируется соединение с SauceLabs.

В любом случае, я надеюсь, что это может помочь кому-то, кто хочет сделать аналогичную «глобальная» параметризация их тестов!

0
ответ дан Danielle Weisz 16 August 2018 в 00:07
поделиться

Вы можете использовать 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)
1
ответ дан Dirk 16 August 2018 в 00:07
поделиться
  • 1
    Пока работает TestSuite, аргументы не передаются в функцию __init__. – jadelord 2 August 2017 в 19:42

Начиная с Python 3.4 для этой цели были введены подтесты для unittest. Подробнее см. В документации . 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 , поэтому он доступен для более ранних версий Python.

39
ответ дан Don Kirkby 16 August 2018 в 00:07
поделиться
  • 1
    Лучшее решение, если вы используете python 3.4 и выше. – Max Malysh 20 December 2015 в 15:14
  • 2
    Используя unittest2, это также доступно для Python 2.7. – Bernhard 25 March 2016 в 17:21
  • 3
    Одно существенное различие между этим подходом и отдельными испытаниями заключается в том, что тестовое состояние не сбрасывается каждый раз. (То есть, setUp() и tearDown() не выполняются между субтестами.) – Kevin Christopher Henry 9 April 2016 в 15:16
  • 4
    @KevinChristopherHenry Да, но self.setUp() можно теоретически вызывать вручную изнутри подтеста. Что касается tearDown, то может быть достаточно, чтобы он автоматически вызывал в конце. – A-B-B 1 May 2017 в 20:33

Это можно решить элегантно, используя метаклассы:

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()
56
ответ дан Guy 16 August 2018 в 00:07
поделиться
  • 1
    Это работало для меня с Selenium. В качестве примечания, в классе TestSequence вы можете определить "static" такие методы, как setUp (self), is_element_present (self, how, what), ... tearDown (self). Помещение их ПОСЛЕ «метаданных» = TestSequenceMeta " кажется, работает. – Love and peace - Joe Codeswell 8 September 2015 в 23:37
  • 2
    Это решение лучше, чем выбранное IMHO. – petroslamb 18 January 2016 в 14:42
  • 3
    Можете ли вы пояснить, почему это не работает, если просто переопределить __new__ из класса TestSequence (и тем самым вообще пропустить метакласс)? – petroslamb 18 January 2016 в 14:50
  • 4
    @petroslamb Метод __new__ в метаклассе вызывается, когда сам класс определяется, а не когда создается первый экземпляр. Я бы предположил, что этот метод динамического создания тестовых методов более совместим с интроспекцией, используемой unittest, для определения количества тестов в классе (т. Е. Он может скомпилировать список тестов, прежде чем он когда-либо создаст экземпляр этого класса). – BillyBBone 23 February 2016 в 05:20
  • 5
    Примечание: в python 3 измените это на: class TestSequence(unittest.TestCase, metaclass=TestSequenceMeta):[...] – Mathieu_Du 30 December 2016 в 19:40

Супер опоздал на вечеринку, но мне не удалось сделать эти работы для 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
ответ дан hhquark 16 August 2018 в 00:07
поделиться

Также существует гипотеза, которая добавляет тестирование на основе fuzz или свойства: https://pypi.python.org/pypi/hypothesis

Это очень мощный метод тестирования.

28
ответ дан Javier 16 August 2018 в 00:07
поделиться
  • 1
    Не удалось выполнить код: TypeError: __init __ () принимает не более 2 аргументов (4 данных) – max 17 November 2015 в 06:31
  • 2
    Добавлены ненулевые значения по умолчанию для дополнительных параметров конструктора. – Javier 24 November 2015 в 02:56
  • 3
    Я предпочитаю код параметризации носа в ответе @ mojo , но для моих клиентов это слишком полезно, чтобы избежать дополнительной зависимости, поэтому я буду использовать это для них. – sage 19 March 2016 в 16:55
  • 4
    Клиент всегда прав! :п – Javier 21 March 2016 в 15:14
  • 5
    Это решение было моим фаворитом на этой странице. Оба параметра Nose , предложенные в текущем верхнем ответе, и его fork Nose2 являются только обслуживанием, а последнее предлагает пользователям вместо этого попробовать pytest . Какой беспорядок - я буду придерживаться такого родного подхода! – Sean 31 January 2018 в 23:00
  • 6
    Я не мог использовать макрос @given() внутри класса unittest. – Egbert S 11 August 2018 в 22:26
  • 7

Я использую метаклассы и декораторы для генерации тестов. Вы можете проверить мою реализацию 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
ответ дан Kirill Ermolov 16 August 2018 в 00:07
поделиться

Помимо использования setattr, мы можем использовать load_tests с python 3.2. Пожалуйста, обратитесь к сообщению в блоге 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
ответ дан kommradHomer 16 August 2018 в 00:07
поделиться

Вы можете использовать плагин нос-ittr (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
4
ответ дан Maroun 16 August 2018 в 00:07
поделиться
  • 1
    Мне нравится этот подход, особенно уровень каждого метода, который он поддерживает. – Matt 6 March 2015 в 02:29

На днях я столкнулся с ParamUnittest , когда смотрел исходный код на использование примера радона ( в github repo ). Он должен работать с другими структурами, расширяющими TestCase (например, Nose).

Вот пример:

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
ответ дан Matt 16 August 2018 в 00:07
поделиться

Это решение работает с unittest и 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
ответ дан mop 16 August 2018 в 00:07
поделиться

Ответы на основе метакласса по-прежнему работают в Python3, но вместо атрибута __metaclass__ нужно использовать параметр metaclass, как в:

class ExampleTestCase(TestCase,metaclass=DocTestMeta):
    pass
0
ответ дан Patrick Ohly 16 August 2018 в 00:07
поделиться

Следующее - мое решение. Я считаю это полезным, когда: 1. Должен работать для unittest.Testcase и unittest обнаружить 2. Попробуйте выполнить набор тестов для разных параметров. 3. Очень простая зависимость от других пакетов 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
ответ дан S.Arora 16 August 2018 в 00:07
поделиться

Это можно сделать, используя pytest . Просто напишите файл 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 и т. Д. ...

25
ответ дан Sergey Voronezhskiy 16 August 2018 в 00:07
поделиться
  • 1
    Я искал простой, простой пример, как параметризовать тестовые примеры с помощью pytest. Большое спасибо! – timgeb 25 March 2016 в 16:13
  • 2
    @timgeb Я рад помочь вам. Проверьте еще раз несколько тегов py.test . Кроме того, я предлагаю использовать hamcrest для добавления сахара в ваши утверждения с помощью читаемых человеком барабанов, которые могут быть модифицированы, объединены или созданы по-своему. Кроме того, у нас есть allure-python , красивое поколение отчетов для py.test – Sergey Voronezhskiy 25 March 2016 в 16:55
  • 3
    Благодарю. Я только начал переходить с unittest на py.test. Раньше у меня были базовые классы TestCase, которые могли динамически создавать детей с разными аргументами, которые они сохраняли бы как переменные класса ... что было немного громоздким. – timgeb 25 March 2016 в 16:57
  • 4
    @timgeb Да, вы правы. Наиболее функцией убийцы из py.test является yield_fixtures . Что можно сделать setup , вернуть некоторые полезные данные в тест и после завершения теста сделать teardown . Светильники также могут быть параметризированы . – Sergey Voronezhskiy 25 March 2016 в 17:08

Просто используйте метаклассы, как показано здесь:

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
ответ дан sleepycal 16 August 2018 в 00:07
поделиться

Мета-программирование - это весело, но может быть в пути. Большинство решений здесь затрудняют:

  • выборочно запускать тестовый
  • пункт обратно к названию данного кода

Итак, мое первое предложение состоит в том, чтобы следовать простому / явному пути (работает с любым тестовым бегуном):

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

Поскольку мы не должны повторять себя, мое второе предложение основывается на ответе @ Хавьера: включите тестирование на основе свойств , Библиотека гипотез:

  • «более неуклонно охарактеризована по поводу генерации тестового случая, чем мы, просто люди»
  • предоставит простые примеры подсчета
  • , работает с любыми test runner
  • имеет гораздо больше интересных функций (статистика, дополнительный тестовый результат, ...) класс TestSequence (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"))

Хорошо, у вас нет разных имен тестов. Но, возможно, вам просто нужно:

  • описательное имя тестируемого свойства.
  • , который приводит к ошибке (пример фальсификации).

Пример Funnier

0
ответ дан YvesgereY 16 August 2018 в 00:07
поделиться
29
ответ дан Javier 5 September 2018 в 23:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: