PyTest-BDD 单一场景概述多个示例

Wal*_*elt 5 python bdd pytest python-behave pytest-bdd

我想定义一个基于 PyTest-BDD 的场景大纲,其中包含多个示例。示例片段:

        Scenario Outline: front to back validation
          When tester executes access view sql query <sqlCommandProp> into av dataframe
          And tester adds investment quant id to av dataframe
          And tester reads raw file <fileNameProp> from datalake into raw dataframe

        @raw2AccessValidation
        Examples:
       |sqlCommandProp|fileNameProp|
       |sqlCommand    | fileName   |

        @raw2AccessValidation2
       Examples:
       |sqlCommandProp|fileNameProp|
       |eric          | shane      |
Run Code Online (Sandbox Code Playgroud)

我想为每个示例都有单独的标签,因为我可能不想运行所有示例。

我已经尝试了上面的方法,发现多个示例都可以。但是,我似乎无法识别不同的标签,因此我无法指定要运行这两个(或更多)中的哪一个。

我问是因为这可以用 java/cucumber 引擎完成。想知道我是否使用 pytest-bdd 遗漏了什么,做错了什么?

谢谢

Ali*_*mir 2

基于这个问题,目前还不支持。

解决方案1:利用标记并将它们注册到 pytest 挂钩中

在上述问题得到解决之前,您可以选择使用 pytest 挂钩并手动注册标记。以下代码迭代所有已注册的测试项,并根据其各自的特征文件在其上注册新标记。它依赖于 pytest-bdd 库的几个内部属性,但它甚至在库内部合并该功能之前就可以有效运行:

# conftest.py

import re
from pathlib import Path
from typing import List

import pytest


def pytest_collection_modifyitems(config: pytest.Config, items: List[pytest.Item]):
    for item in items:
        if not hasattr(item, "_pyfuncitem") or not hasattr(item, "callspec"):
            continue

        feature = item._pyfuncitem._obj.__scenario__.feature
        feature_content_lines = Path(feature.filename).read_text().splitlines()

        parameters = list(item.callspec.params["_pytest_bdd_example"].values())

        examples_start_line = None
        for i, line in enumerate(feature_content_lines):
            if "Examples:" in line:
                examples_start_line = i
                continue
            elif re.match(r"[|\s]+{}[|\s]+".format(r"[|\s]+".join(parameters)), line):
                break

        if examples_start_line is None:
            continue

        tag_match = re.search(
            r"@(?P<tag>\S+)", feature_content_lines[examples_start_line - 1]
        )

        if tag_match is None:
            continue

        tag = tag_match.group("tag")

        item.add_marker(tag)
Run Code Online (Sandbox Code Playgroud)

考虑以下功能文件:

Feature: Scenario outlines
    Scenario Outline: Outlined given, when, then
        Given there are <start> cucumbers
        When I eat <eat> cucumbers
        Then I should have <left> cucumbers

        @part1
        Examples:
        | start | eat | left |
        |  12   |  5  |  7   |
        |  12   |  4  |  8   |

        @part2
        Examples:
        | start | eat | left |
        |  11   |  5  |  6   |
Run Code Online (Sandbox Code Playgroud)

以及以下测试文件:

# test_scenario_outlines.py

from pytest_bdd import given, parsers, scenarios, then, when

scenarios("scenario_outlines.feature")


@given(parsers.parse("there are {start:d} cucumbers"), target_fixture="cucumbers")
def given_cucumbers(start):
    return {"start": start, "eat": 0}


@when(parsers.parse("I eat {eat:d} cucumbers"))
def eat_cucumbers(cucumbers, eat):
    cucumbers["eat"] += eat


@then(parsers.parse("I should have {left:d} cucumbers"))
def should_have_left_cucumbers(cucumbers, left):
    assert cucumbers["start"] - cucumbers["eat"] == left
Run Code Online (Sandbox Code Playgroud)

您可以简单地使用标记来运行特定的示例记录:

pytest . -m part1
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

pytest . -m part2
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

注意:您应该注册标记以防止 pytest 警告。

解决方案 2:使用参数作为标签

您可以向参数表添加新列,并指定标签:

# scenario_outlines.feature

Feature: Scenario outlines
    Scenario Outline: Outlined given, when, then
        Given there are <start> cucumbers
        When I eat <eat> cucumbers
        Then I should have <left> cucumbers

        Examples:
        | start | eat | left |   tag   |
        |  12   |  5  |  7   |  part1  |
        |  12   |  4  |  8   |  part1  |

        Examples:
        | start | eat | left |   tag   |
        |  11   |  5  |  6   |  part2  |
Run Code Online (Sandbox Code Playgroud)

无需编辑Python测试文件或关注tag代码中的参数。相反,只需利用该-k选项有选择地选择具有特定标签值的记录:

pytest . -k part1
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

pytest . -k part2
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述