Как проверить то же утверждение на большое количество данных

StackOverflow https://stackoverflow.com/questions/3915232

Вопрос

Я использую модуль Python Unittest для проведения ряда тестов; Однако это очень повторяющееся.

У меня есть много данных, которые я хочу проходить через один и тот же тест снова и снова, проверяя, если правильно. Тем не менее, я должен определить тест на каждого.

Например, я хочу сделать что -то похожее на это. Я знаю, что мог бы сделать это с помощью генератора (нашел его в предыдущем потоке здесь). Но есть ли альтернативы, может быть, даже использование другого модуля тестирования?

Любые предложения были бы великолепны.


import unittest

class TestData(unittest.TestCase):
    def testNumbers(self):
        numbers = [0,11,222,33,44,555,6,77,8,9999]
        for i in numbers:
            self.assertEqual(i, 33)
Это было полезно?

Решение 5

В другом посте я наткнулсяТесты носаЭто больше подходит для тестирования, управляемого данными.


class Test_data():
    def testNumbers():
        numbers = [0,11,222,33,44,555,6,77,8,9999]
        for i in numbers:
            yield checkNumber, num

def checkNumber(num):
    assert num == 33

Приведенный выше код делает то же самое, что и мой первый пост. Импорт не требуется, просто напишите класс Python.

Вы выполняете тесты, набрав:

nosetests filename

Другие советы

Пример кода для решения, предложенный Биллом Грибблом, может выглядеть так:

import unittest

class DataTestCase(unittest.TestCase):
    def __init__(self, number):
        unittest.TestCase.__init__(self, methodName='testOneNumber')
        self.number = number

    def testOneNumber(self):
        self.assertEqual(self.number, 33)

    def shortDescription(self):
        # We need to distinguish between instances of this test case.
        return 'DataTestCase for number %d' % self.number


def get_test_data_suite():
    numbers = [0,11,222,33,44,555,6,77,8,9999]
    return unittest.TestSuite([DataTestCase(n) for n in numbers])

if __name__ == '__main__':
    testRunner = unittest.TextTestRunner()
    testRunner.run(get_test_data_suite())

Вы можете рассмотреть возможность использования класса unittest.testsuite, который позволит вам динамически построить набор экземпляров unittest.testcase, которые будут выполняться отдельно. Ваш подкласс unittest.testcase должен определить только один метод испытаний, причем класс принимает параметр конструкции, проходящий в значении для проверки для этого конкретного экземпляра.

То ddt библиотека был построен, чтобы решить именно то, о чем вы просите unittest[*].

Например:

import ddt
import unittest

@ddt.ddt
class EvalTests(unittest.TestCase):

    @ddt.data(
            ('1', 1),
            ('1 == 1',  True),
            ('1 == 2',  False),
            ('1 + 2',   4),  ## This will fail
    )
    def test_eval_expressions(self, case):
        expr, exp_value = case
        self.assertEqual(eval(expr), exp_value)

И когда вы запустите его, вы получаете 4 тестовых палата вместо одного:

$ python -m unittest  -v  test_eval.py
test_eval_expressions_1___1___1_ (test_eval.EvalTests) ... ok
test_eval_expressions_2___1__1___True_ (test_eval.EvalTests) ... ok
test_eval_expressions_3___1__2___False_ (test_eval.EvalTests) ... ok
test_eval_expressions_4___1_2___4_ (test_eval.EvalTests) ... FAIL

======================================================================
FAIL: test_eval_expressions_4___1_2___4_ (test_eval.EvalTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python/lib/site-packages/ddt.py", line 129, in wrapper
    return func(self, *args, **kwargs)
  File "/Work/test_eval.py", line 15, in test_eval_expressions
    self.assertEqual(eval(expr), exp_value)
AssertionError: 3 != 4

----------------------------------------------------------------------
Ran 4 tests in 0.002s

FAILED (failures=1)

Заметь ДДТ пытается придумать имена для сгенерированных TCS.

Установите его с PIP:

pip install ddt

*] То же решение для питонического pytest рамки (pytest.mark.parametrize) интегрируется в основной инструмент и стоит переключиться на pytest Только для этой функции.

Проблема с управлением утверждениями в цикле заключается в том, что, если одно из утверждений не удается, вы не знаете, какое значение вызвано его (в вашем примере это не удалось бы 0, но вы этого не знаете, пока не отлаживаете). С другой стороны, повторяя self.assertEqual(i, 33) это еще хуже, потому что она вводит дублирование кода.

Что я делаю в своем тесте, так это создать простую, вскоре названную внутреннюю функцию внутри теста и называть ее с разными аргументами. Так что ваша функция будет выглядеть так:

import unittest

class TestData(unittest.TestCase):
    def testNumbers(self):
        def eq(i):
            self.assertEqual(i, 33)
        eq(0)
        eq(11)
        eq(222)
        eq(33)
        eq(44)
        eq(555)
        ... 

Таким образом, когда утверждение не удается 0, вы сразу же видите его на трассировке, напечатанном unittest модуль.

Начиная с Python 3.4 вы можете использовать unittest.TestCase.subTest(msg=None, **params) Контекст -менеджер (документация). Это позволит вам достичь того, что вы хотите, добавив только одно заявление.

Вот ваш пример, измененный для использования subTest()

import unittest

class TestData(unittest.TestCase):
    def testNumbers(self):
        numbers = [0, 11, 222, 33, 44, 555, 6, 77, 8, 9999]
        for i in numbers:
            with self.subTest(i=i):  # added statement
                self.assertEqual(i, 33)

Поступок это Ответ, который не сработал для меня. Где я не имею дело большой Количество данных мне нужно было запустить те же тесты с различными входами. Следующие тесты используются create_a и create_b Методы, которые я хочу настроить.

Требование состоит в том, чтобы запустить оба теста с одинаковой настройкой.

class Tests(unittest.TestCase):

    def test_a_uses_b(self):
        a = create_a()
        b = create_b()
        a.b = b
        self.assertIs(b.a, a)

    def test_b_uses_a(self):
        a = create_a()
        b = create_b()
        b.a = a
        self.assertIs(a.b, b)

Мгновенный TestSuite и TestCase Я сам обходил тестовый загрузчик, привел к ошибке, потому что он ожидал одного метода, вызванного runTest.

Результатом было следующее:

class Tests(unittest.TestCase):

    def __init__(self, create_a, create_b):
        super().__init__()
        self.create_b = create_b
        self.create_a = create_a

    def test_a_uses_b(self):
        a = self.create_a()
        b = self.create_b()
        a.b = b
        self.assertIs(b.a, a)

    def test_b_uses_a(self):
        a = self.create_a()
        b = self.create_b()
        b.a = a
        self.assertIs(a.b, b)


class TestPair1(Tests):
    def __init__(self):
        super().__init__(create_a1, create_b1)


class TestPair2(Tests):
    def __init__(self):
        super().__init__(create_a2, create_b2)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top