我有一个测试,我希望作为两个不同测试套件的一部分运行,并根据测试套件提供不同的参数输入。测试套件用pytest标记识别。
有没有办法标记参数化条目,以便它们只在特定的测试套件中运行?
以下是我想做的事情:
@pytest.mark.suiteA # include the test in Suite A
@pytest.mark.suiteB # include the test in Suite B
@pytest.mark.parametrize("inputParameter", [
(10), # use this input for Suites A and B
pytest.mark.suiteB(12)]) # only use this input for Suite B
def test_printInputParameter(inputParameter):
print inputParameter
运行这样的代码不会产生我想要的结果 - 两个输入都用于两个套件。
我已经看到pytest将允许在参数化中使用xfail或跳过(参见http://pytest.org/latest/skipping.html上的“使用参数化跳过/ xfail”)如果有办法编写条件语句,只有在运行Suite B,也可以实现我的需要。
提前感谢您的帮助。
答案 0 :(得分:1)
您处在正确的轨道上。问题的一部分是您已经用suiteA和suiteB标记了测试功能,因此该功能被视为两者的一部分。
您正在使用的参数标记样式可能在'14时代就可以使用(直到pytest 3仍可使用),但在最新的pytest版本(5.x)中则无效。
这些示例使用最新样式,该样式至少也可以追溯到pytest 3.x。
使用参数设置时,应用标记将使其应用于每个单独的测试。但是,也可以将标记应用于单个测试实例:
import pytest @pytest.mark.foo @pytest.mark.parametrize( ("n", "expected"), [(1, 2), pytest.param(1, 3, marks=pytest.mark.bar), (2, 3)] ) def test_increment(n, expected): assert n + 1 == expected
在上面的示例中,使用标记 foo 将运行该测试,所有参数(包括bar)都将被测试。使用标记 bar 将仅使用标记为1的参数运行该测试。
因此,以您的示例为例,您可以这样做(请原谅,我将除标记之外的所有名称都更新为PEP8标准):
@pytest.mark.parametrize("input_parameter", [
# use this input for Suite A and Suite B
pytest.param(10, marks=[pytest.mark.suiteA, pytest.mark.suiteB]),
# use this input only for Suite B
pytest.param(12, marks=pytest.mark.suiteB),
# this input will run when no markers are specified
(13),
])
def test_print_input_parameter(input_parameter):
print(input_parameter)
您必须摆脱函数上方的两个标记修饰符。您只需要此参数修饰符。
根据注释,将输入10标记为可确保仅与suiteA或suiteB一起运行。如果需要调用其中一个或两个,它将执行。
输入12绑定到单个标记suiteB。仅在需要suiteB时才会执行。
我还添加了输入值13作为默认未标记测试运行的示例。正常情况下,这不会对suiteA或suiteB(或suiteC或任何其他标记过滤器)执行,但是如果未指定标记(其余的标记),它将运行。
或者,您可以执行以下操作:
@pytest.mark.suiteB # this function is a part of suiteB
@pytest.mark.parametrize("input_parameter", [
# use this input for Suite A and Suite B
pytest.param(10, marks=pytest.mark.suiteA),
# use this input only for Suite B
(12),
# this input is also part of Suite B thanks to the function decorator, as well as suiteC and suiteD
pytest.param(13, marks=[pytest.mark.suiteC, pytest.mark.suiteD]),
])
def test_print_input_parameter(input_parameter):
print(input_parameter)
使用原始的两个参数,您实际上进行了完整的suiteB测试,其中一个参数仅适用于suiteA。
在这种情况下,函数装饰器在suiteB下运行整个测试。如果指定suiteA,将仅执行10个。
因为使用了函数装饰器,所以我组成的参数13像该函数的所有参数一样,也是suiteB的一部分。我可以根据需要将其添加到其他标记中,但是函数装饰器可确保此测试将在suiteB下使用所有参数运行。
在您的示例中,该替代方法也可以使用,但是如果您有任何不重叠的参数(例如,在suiteB下运行13是 not ),则必须像中间的例子。
答案 1 :(得分:0)
好像你可以使用http://pytest.org/latest/skipping.html#skip-xfail-with-parametrize(你所指的)中描述的skipif标记来做到这一点。您需要做的就是知道您的代码是否在suiteA或suiteB中运行,您可能已经拥有suiteA
和SuiteB
标记。因此,对于示例,让我们在sys
模块上设置一个(丑陋的)辅助属性,就像检测代码是否在py.test下运行一样:
# E.g. in conftest.py; in real life the value probably comes from a
# command line option added by pytest_addoption()
def pytest_configure(config):
sys._my_test_suite = 'A' # or 'B'
# The actual test can now use this in skipif
@pytest.mark.suiteA # include the test in Suite A
@pytest.mark.suiteB # include the test in Suite B
@pytest.mark.parametrize(
"inputParameter",
[(10), pytest.mark.skipif(sys._my_test_suite == 'A', reason='suite A only')(12)])])
def test_printInputParameter(inputParameter):
print inputParameter
是的,在sys模块上设置一个属性是一个丑陋的黑客,但对于这种情况它是一个简单的解决方案。
答案 2 :(得分:0)
使用@ pytest.mark.suiteX可以使所有参数化测试都带有该标记,因此实际上,您已经标记了所有测试,而仅在参数列表内应用标记:
import pytest
mark = pytest.mark
@mark.parametrize("inputParameter", [
mark.suiteA(10),
mark.suiteB(12),
])
def test_printInputParameter(inputParameter):
print inputParameter
然后在cli上使用-m(标记)选择要过滤的测试:
bash-4.4$ pytest -m suiteA test_in.py -sv
test_in.py::test_printInputParameter[10] 10
PASSED
bash-4.4$ pytest -m suiteB test_in.py -sv
test_in.py::test_printInputParameter[12] 12
PASSED