首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将行为整合到pytest中?

如何将行为整合到pytest中?
EN

Stack Overflow用户
提问于 2016-12-14 15:44:58
回答 2查看 8.5K关注 0票数 22

我创建了一个Django应用程序,并且非常依赖pytest来发现和组织我的单元和功能测试。但是,我希望在未来的测试中应用behave开发驱动的行为。不幸的是,behave测试特性不能由pytest自动检测.

如何将behave pytest 及其测试集成到pytest发现、执行和报告中?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-12-14 20:18:58

Pytest和是两个独立的测试运行程序。

有一个用于行为测试的pytest插件,它也使用Gherkin作为DSL,但是这些步骤的实现使用了与行为不同的语法,所以我认为您不能直接运行用它创建的步骤。

票数 13
EN

Stack Overflow用户

发布于 2021-02-19 20:24:02

遵循pytest文档示例,您可以实现如下的输出:

代码语言:javascript
运行
复制
______________________________________________________________ Feature: Fight or flight  - Scenario: Stronger opponent ______________________________________________________________

Feature: Fight or flight
  Scenario: Stronger opponent
    Step [OK]: the ninja has a third level black-belt
    Step [ERR]: attacked by Chuck Norris
      Traceback (most recent call last):
        File ".venv/lib/python3.6/site-packages/behave/model.py", line 1329, in run
          match.run(runner.context)
        File ".venv/lib/python3.6/site-packages/behave/matchers.py", line 98, in run
          self.func(context, *args, **kwargs)
        File "tests/bdd/steps/tutorial.py", line 23, in step_impl4
          raise NotImplementedError('STEP: When attacked by Chuck Norris')
      NotImplementedError: STEP: When attacked by Chuck Norris
    Step [NOT REACHED]: the ninja should run for his life

使用来自行为教程的特性文件

为了使pytest运行正常,可以在conftest.py中使用以下代码片段

代码语言:javascript
运行
复制
# content of conftest.py

import pytest


class BehaveException(Exception):
    """Custom exception for error reporting."""

def pytest_collect_file(parent, path):
    """Allow .feature files to be parsed for bdd."""
    if path.ext == ".feature":
        return BehaveFile.from_parent(parent, fspath=path)

class BehaveFile(pytest.File):
    def collect(self):
        from behave.parser import parse_file
        feature = parse_file(self.fspath)
        for scenario in feature.walk_scenarios(with_outlines=True):
            yield BehaveFeature.from_parent(
                self,
                name=scenario.name,
                feature=feature,
                scenario=scenario,
            )


class BehaveFeature(pytest.Item):

    def __init__(self, name, parent, feature, scenario):
        super().__init__(name, parent)
        self._feature = feature
        self._scenario = scenario

    def runtest(self):
        import subprocess as sp
        from shlex import split

        feature_name = self._feature.filename
        cmd = split(f"""behave tests/bdd/ 
            --format json 
            --no-summary
            --include {feature_name}
            -n "{self._scenario.name}"
        """)

        try:
            proc = sp.run(cmd, stdout=sp.PIPE)
            if not proc.returncode:
                return
        except Exception as exc:
            raise BehaveException(self, f"exc={exc}, feature={feature_name}")

        stdout = proc.stdout.decode("utf8")
        raise BehaveException(self, stdout)

    def repr_failure(self, excinfo):
        """Called when self.runtest() raises an exception."""
        import json
        if isinstance(excinfo.value, BehaveException):
            feature = excinfo.value.args[0]._feature
            results = excinfo.value.args[1]
            data = json.loads(results)
            summary = ""
            for feature in data:
                if feature['status'] != "failed":
                    continue
                summary += f"\nFeature: {feature['name']}"
                for element in feature["elements"]:
                    if element['status'] != "failed":
                        continue
                    summary += f"\n  {element['type'].title()}: {element['name']}"
                    for step in element["steps"]:
                        try:
                            result = step['result']
                        except KeyError:
                            summary += f"\n    Step [NOT REACHED]: {step['name']}"
                            continue
                        status = result['status']
                        if status != "failed":
                            summary += f"\n    Step [OK]: {step['name']}"
                        else:
                            summary += f"\n    Step [ERR]: {step['name']}"
                            summary += "\n      " + "\n      ".join(result['error_message'])

            return summary

    def reportinfo(self):
        return self.fspath, 0, f"Feature: {self._feature.name}  - Scenario: {self._scenario.name}"

注意:

  1. 需要正确的状态解码(如将featureelementstep状态与behave.model_core.Status中的Enum进行比较)
  2. 这个片段将调用behave作为子过程,而不是它的内部API。一个合适的移民应该考虑
    1. 从同一进程中子类behave.runner:Runnerbehave.runner:ModelRunner和触发器。
    2. 在repr_failure中使用行为格式化程序,而不是手动解码json输出

  3. 您可以通过针对整个特性或特定步骤来实现更多/更少的粒度,但此片段仅为场景演示。
  4. 因为(1),你不会收集数据(如为了覆盖目的).
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41146633

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档