Py.test:参数化来自 类 的测试用例

Py.test: parametrize test cases from classes

我目前正在关注这个 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 个测试?

如果您从 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

尽管如此,这有点回避了您为什么使用 类 而不是仅仅定义函数的问题,因为测试本质上是相同的,但需要更少的整体样板和代码。

最后,考虑到@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

我不知道 5 年前是不是这样,但现在你可以使用参数化 (https://pypi.org/project/parameterized/) 和 pytest 来装饰测试中的测试方法 class,是的,包括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 错误输出中获取名称

对于那些仍然感兴趣的人,我写了一个插入式@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]