Python 如何使用py.test对多个项目执行多个测试

Python 如何使用py.test对多个项目执行多个测试,python,pytest,Python,Pytest,我是python和py.test的新手。我正在搜索对多个项目运行多个测试的方法,但找不到它。如果你知道怎么做,我相信这很简单 我简化了我要做的事情,使之更容易理解 如果我有一个定义了一系列测试的测试类,比如: class SeriesOfTests: def test_greater_than_30(self, itemNo): assert (itemNo > 30), "not greather than 30" def test_lesser_than

我是python和py.test的新手。我正在搜索对多个项目运行多个测试的方法,但找不到它。如果你知道怎么做,我相信这很简单

我简化了我要做的事情,使之更容易理解

如果我有一个定义了一系列测试的测试类,比如:

class SeriesOfTests:
    def test_greater_than_30(self, itemNo):
        assert (itemNo > 30), "not greather than 30"
    def test_lesser_than_30(self, itemNo):
        assert (itemNo < 30), "not lesser thant 30"
    def test_modulo_2(self, itemNo):
        assert (itemNo % 2) == 0, "not divisible by 2"
我试图得到的结果是:

RESULT : 
Test "itemNo = 0"
  - test_greater_than_30 = failed
  - test_lesser_than_30 = success
  - test_modulo_2 = success

Test "itemNo = 11"
  - test_greater_than_30 = failed
  - test_lesser_than_30 = success
  - test_modulo_2 = failed

Test "itemNo = 33"
  - test_greater_than_30 = success
  - test_lesser_than_30 = failed
  - test_modulo_2 = failed
如何使用py.test实现这一点

比你们男人(女孩也一样)

安德烈使用:

使用
-v--tb=no
选项

例如:

=================================================测试会话开始==============================
平台linux2--python2.7.5--pytest-2.3.5--/usr/bin/Python
收集9项
测试样本。py:26:测试项目编号[0-大于30]失败
测试样本。py:26:测试项目编号[0-小于30]通过
测试样本。py:26:测试项目编号[0-模2]通过
测试样本。py:26:测试项目编号[11-大于30]失败
测试样本。py:26:测试项目编号[11-小于30]通过
测试样本。py:26:测试项目编号[11-模2]失败
测试样本。py:26:测试项目编号[33-大于30]通过
测试样本。py:26:测试项目编号[33-小于30]失败
测试样本。py:26:测试项目编号[33-模2]失败
==================================5次失败,4次在0.03秒内通过======================

请参见

忘记前面的答案。如果需要按值对测试进行分组,则可以使用。我刚刚改编了文档中的示例:

import pytest

def pytest_generate_tests(metafunc):
    idlist = []
    argvalues = []
    for scenario in metafunc.cls.scenarios:
        idlist.append(scenario[0])
        items = scenario[1].items()
        argnames = [x[0] for x in items]
        argvalues.append(([x[1] for x in items]))
    metafunc.parametrize(argnames, argvalues, ids=idlist, scope="class")

scenario1 = ('itemNo = 0', {'itemNo': 0})
scenario2 = ('itemNo = 11', {'itemNo': 11})
scenario3 = ('itemNo = 33', {'itemNo': 33})

class TestSeries:
    scenarios = [scenario1, scenario2, scenario3]
    
    def test_greater_than_30(self, itemNo):
        assert (itemNo > 30), "not greather than 30"
    def test_lesser_than_30(self, itemNo):
        assert (itemNo < 30), "not lesser thant 30"
    def test_modulo_2(self, itemNo):
        assert (itemNo % 2) == 0, "not divisible by 2"

我想这是你能得到的最接近的结果。

对不起,这并不是我想要的结果。结果必须显示itemNo的每个函数的失败(或成功)。在您的示例中,它显示了函数的每个itemNo的失败。@AndréGodin,我更新了答案。它会给你你想要的。(使用
-v--tb=no
选项)感谢您的努力,但同样,您的结果不是按itemNo分组的。是否有可能将其分组,以显示某个itemNo的每个测试方法的结果,然后继续第二个itemNo,依此类推?请参考我的结果I示例want@AndréGodin是一个使用
pytest.mark.parametrize
itertools.product
的替代方案。我必须承认它是有效的。。。我只是不明白这是怎么回事:)谢谢你。我能请你简单地解释一下吗。。。对于新手,我是:)对不起,但就像我对falsetru说的,我希望结果按itemNo分组。这更像是我希望。。。现在我只需要一种从函数getItemNo()的结果动态生成场景列表的方法……我最终将使用您的答案,因为它几乎完成了,而且更容易理解。。。我们只需要将场景定义替换为:scenarios=[]for getItemNo()中的itemNo:scenarios.append(((“item no{}.format(itemNo),{'itemNo':itemNo}));
import pytest

@pytest.fixture(params=[0, 11, 33])
def itemNo(request):
    return request.param

def test_greater_than_30(itemNo):
    assert (itemNo > 30), "not greather than 30"
def test_lesser_than_30(itemNo):
    assert (itemNo < 30), "not lesser thant 30"
def test_modulo_2(itemNo):
    assert (itemNo % 2) == 0, "not divisible by 2"
import pytest

class FunctionWrapper(str):
    def __init__(self, f):
        self.f = f
    def __call__(self, *args, **kwargs):
        return self.f(*args, **kwargs)
    def __str__(self):
        return self.f.__name__

def greater_than_30(itemNo):
    assert (itemNo > 30), "not greater than 30"
def lesser_than_30(itemNo):
    assert (itemNo < 30), "not lesser thant 30"
def modulo_2(itemNo):
    assert (itemNo % 2) == 0, "not divisible by 2"

@pytest.fixture(params=[0, 11, 33])
def itemNo(request):
    return request.param

@pytest.fixture(params=map(FunctionWrapper, [
    greater_than_30, lesser_than_30, modulo_2
]))
def assertion_func(request):
    return request.param

def test_item_no(itemNo, assertion_func):
    assertion_func(itemNo)
import pytest

def pytest_generate_tests(metafunc):
    idlist = []
    argvalues = []
    for scenario in metafunc.cls.scenarios:
        idlist.append(scenario[0])
        items = scenario[1].items()
        argnames = [x[0] for x in items]
        argvalues.append(([x[1] for x in items]))
    metafunc.parametrize(argnames, argvalues, ids=idlist, scope="class")

scenario1 = ('itemNo = 0', {'itemNo': 0})
scenario2 = ('itemNo = 11', {'itemNo': 11})
scenario3 = ('itemNo = 33', {'itemNo': 33})

class TestSeries:
    scenarios = [scenario1, scenario2, scenario3]
    
    def test_greater_than_30(self, itemNo):
        assert (itemNo > 30), "not greather than 30"
    def test_lesser_than_30(self, itemNo):
        assert (itemNo < 30), "not lesser thant 30"
    def test_modulo_2(self, itemNo):
        assert (itemNo % 2) == 0, "not divisible by 2"
$ py.test -v
============ test session starts ==============================================
platform linux2 -- Python 2.7.4 -- pytest-2.4.2 -- /home/jose/.virtualenvs/pytest1/bin/python
collected 9 items 

test_first.py:23: TestSeries.test_greater_than_30[itemNo = 0] FAILED
test_first.py:25: TestSeries.test_lesser_than_30[itemNo = 0] PASSED
test_first.py:27: TestSeries.test_modulo_2[itemNo = 0] PASSED
test_first.py:23: TestSeries.test_greater_than_30[itemNo = 11] FAILED
test_first.py:25: TestSeries.test_lesser_than_30[itemNo = 11] PASSED
test_first.py:27: TestSeries.test_modulo_2[itemNo = 11] FAILED
test_first.py:23: TestSeries.test_greater_than_30[itemNo = 33] PASSED
test_first.py:25: TestSeries.test_lesser_than_30[itemNo = 33] FAILED
test_first.py:27: TestSeries.test_modulo_2[itemNo = 33] FAILED