【问题标题】:Mark inputs in pytest parametrize在 pytest 参数化中标记输入
【发布时间】:2014-09-02 02:47:19
【问题描述】:

我有一个测试,我想作为两个不同测试套件的一部分运行,并根据测试套件使用不同的参数输入。测试套件使用 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”)如果有一种方法可以编写一个条件语句,该语句仅在运行套件时评估为真B,那也能满足我的需要。

提前感谢您的帮助。

【问题讨论】:

    标签: python pytest


    【解决方案1】:

    你在正确的轨道上。部分问题在于您已使用套件 A 和套件 B 标记了测试函数,因此该函数被视为两者的一部分。

    您使用的参数标记样式可能在 14 年有效(并且在 pytest 3 后期仍然有效),但在最新的 pytest 版本 (5.x) 中无效。

    这些示例使用最新的样式,至少可以追溯到 pytest 3.x。

    来自the pytest docs

    使用参数化时,应用标记将使其应用于每个单独的测试。但是,也可以将标记应用于单个测试实例:

    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)
    

    你必须去掉函数上面的两个标记装饰器。你只需要这个参数装饰器。

    根据 cmets,输入 10 被标记以确保它只能与套件 A 或套件 B 一起运行。如果调用其中一个或两个,它将执行。

    输入 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)
    

    使用您原来的两个参数,您确实有一个完整的套件 B 测试,其中一个参数仅适用于套件 A。

    在这种情况下,函数装饰器在 suiteB 下运行整个测试。如果指定了suiteA,只会执行10个。

    因为用到了函数装饰器,所以我编的参数13,和这个函数的所有参数一样,也是suiteB的一部分。我可以将它添加到任意数量的其他标记中,但函数装饰器确保此测试将使用 suiteB 下的所有参数运行。

    根据您的示例,此替代方案将起作用,但如果您有任何不重叠的参数(例如,13 是 not 在 suiteB 下运行),您必须单独指定它们中的每一个,例如中间的例子。

    【讨论】:

      【解决方案2】:

      您似乎可以使用 http://pytest.org/latest/skipping.html#skip-xfail-with-parametrize 中所述的 skipif 标记来执行此操作(您所指的)。您需要做的就是知道您的代码是在suiteA 还是suiteB 中运行,因为suiteASuiteB 标记工作,您可能已经拥有了。因此,对于示例,让我们在 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 模块上设置一个属性是一个丑陋的 hack,但对于这种情况,这是一个简单的解决方案。

      【讨论】:

        【解决方案3】:

        您使用@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
        

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-06-27
        • 2020-12-13
        • 1970-01-01
        • 2023-02-21
        • 1970-01-01
        • 2023-02-15
        • 2016-12-25
        • 1970-01-01
        相关资源
        最近更新 更多