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]
我目前正在关注这个 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.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]