Py.test:从类中参数化测试用例

时间:2016-02-22 19:08:58

标签: python unit-testing automated-tests pytest

我目前正在关注这个py.test示例,当我不使用类时,它会解决,但是当我将测试用例引入类时,我失败了。

我设法编写的最小案例如下:

import unittest

import pytest

class FixtureTestCase(unittest.TestCase):

    @pytest.mark.parametrize("test_input,expected", [
    ("3+5", 8),
    ("2+4", 6),
    ("6*9", 42),
    ])
    def test_1(self, a, b):
        self.assertEqual(a, b)
不幸的是,当我执行

  py.test  test_suite.py

我收到错误消息:

  TypeError: test_1() takes exactly 3 arguments (1 given)

如何生成一系列test_1测试?

4 个答案:

答案 0 :(得分:12)

如果您从unittest.TestCase继承,则您的测试方法不能有其他参数。如果您只是从object继承,它将起作用(尽管您必须使用常规assert语句而不是TestCase.assertEqual方法。

import unittest

import pytest

class TestCase(object):

    @pytest.mark.parametrize("test_input,expected", [
    ("3+5", 8),
    ("2+4", 6),
    ("6*9", 42),
    ])
    def test_1(self, a, b):
        assert eval(a) == b

但是,在这一点上,有点问题为什么你使用类而不是仅仅定义函数,因为测试基本上是相同的,但需要更少的整体样板和代码。

答案 1 :(得分:1)

对于那些仍然感兴趣的人,我写了一个 @pytest.mark.parametrize 替换 unittest.TestCase:https://github.com/MrMrRobat/parametrize

import unittest

from parametrize import parametrize

class FixtureTestCase(unittest.TestCase):

    @parametrize(
        "test_input,expected",
        [
            ("3+5", 8),
            ("2+4", 6),
            ("6*9", 42),
        ]
    )
    def test_1(self, test_input, expected):
        self.assertEqual(eval(test_input), expected)

$ pytest test.py::FixtureTestCase::test_1

Test session starts (platform: darwin, Python 3.9.4, pytest 6.2.4, pytest-sugar 0.9.4)
plugins: sugar-0.9.4, cov-2.11.1, mock-3.6.0
collecting ... 
 test.py ✓✓                                                       67% ██████▋   

―――――――――――――――――――――――― FixtureTestCase.test_1[6*9-42] ――――――――――――――――――――――――

self = <test.FixtureTestCase testMethod=test_1[6*9-42]>, test_input = '6*9'
expected = 42

    @parametrize(
        "test_input,expected",
        [
            ("3+5", 8),
            ("2+4", 6),
            ("6*9", 42),
        ]
    )
    def test_1(self, test_input, expected):
>       self.assertEqual(eval(test_input), expected)
E       AssertionError: 54 != 42

test.py:16: AssertionError

 test.py ⨯                                                       100% ██████████
=========================== short test summary info ============================
FAILED test.py::FixtureTestCase::test_1[6*9-42] - AssertionError: 54 != 42

Results (0.09s):
       2 passed
       1 failed
         - test.py:7 FixtureTestCase.test_1[6*9-42]

答案 2 :(得分:0)

最后,考虑到@Brendan Abel的回复和评论,我成功完成了我打算做的事情:

class TestCase(object):

    @parameterized.expand([
    ("negative", -1.5, -2.0),
    ("integer", 1, 1.0),
    ("large fraction", 1.6, 1),
    ])
    def test_floor(self, name, input, expected):
        assert_equal(math.floor(input), expected)


    @parameterized.expand([
    ("3+5", 8),
    ("2+4", 6),
    ("6*9", 42),
    ])
    def test_1(self, a, b):
        assert_equal(eval(a), b)

然后我可以通过nosetests命令执行测试:

  nosetests -v --with-id class.py

答案 3 :(得分:0)

我不知道 5 年前是否是这种情况,但是现在您可以使用参数化 (https://pypi.org/project/parameterized/) 和 pytest 来装饰测试类上的测试方法,是的,包括 unittest.TestCase,而无需求助于鼻子。例如:

from unittest import TestCase
from parameterized import parameterized

class SomeTestCase(TestCase):

    @parameterized.expand([
        (1, 2),
        ('a', 'b')
    ])
    def test_something(self, param1, param2):
        ...

唯一的问题,但您最好记住这一点,装饰器将为每个列出的输入参数生成新的测试方法,因此您将无法通过在命令行中指定来直接运行原始测试方法。例如。 pytest some_test.py::SomeTestCase::test_something 将不再起作用(因为您的测试方法现在需要两个参数)。但是,您可以直接调用生成的方法,您可以在运行整个 TestCase 或执行 pytest --collect-only 时从 pytest 错误输出中获取名称。