IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> Pytest-使用已有测试套件以及断言 -> 正文阅读

[开发测试]Pytest-使用已有测试套件以及断言

pytest 使用已有的测试套件

Pytest 可以与大多数现有的测试套件一起使用,但它的行为与其他测试运行程序不同,例如nose 或 Python 的默认单元测试框架。

使用 pytest 运行现有的测试套件

假设您想为某个地方的现有存储库做出贡献。在使用某种版本控制和(可选)设置 virtualenv 将代码拉入您的开发空间后,您将要运行:

cd <repository>
pip install -e .  # Environment dependent alternatives include
                  # 'python setup.py develop' and 'conda develop'

在您的项目根目录中。这将在site-packages中为您的代码设置一个符号链接,允许您在测试运行时编辑您的代码,就像它已安装一样。

在开发模式下设置您的项目可以让您避免每次想要运行测试时都必须重新安装,并且比使用 sys.path 将测试指向本地代码更容易。

测试中断言的编写和报告

使用 assert 语句断言

pytest 允许您使用标准的 python 断言来验证 Python 测试中的期望值和实际值。例如,您可以编写以下内容:

# content of test_assert1.py
def f():
    return 3


def test_function():
    assert f() == 4

断言您的函数返回某个值。如果此断言失败,您将看到函数调用的返回值:

$ pytest test_assert1.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 1 item

test_assert1.py F                                                    [100%]

================================= FAILURES =================================
______________________________ test_function _______________________________

    def test_function():
>       assert f() == 4
E       assert 3 == 4
E        +  where 3 = f()

test_assert1.py:6: AssertionError
========================= short test summary info ==========================
FAILED test_assert1.py::test_function - assert 3 == 4
============================ 1 failed in 0.12s =============================

pytest 支持显示最常见的子表达式的值,包括调用、属性、比较以及二元和一元运算符。这允许您在不丢失内省信息的情况下使用没有样板代码的惯用 python 结构。

但是,如果您使用这样的断言指定消息:

assert a % 2 == 0, "value was odd, should be even"

那么根本不会发生断言内省,消息将简单地显示在跟踪信息中。

有关断言自省的更多信息,请参阅断言自省详细信息

关于预期异常的断言

为了编写关于引发异常的断言,您可以使用 pytest.raises() 作为上下文管理器,如下所示:

import pytest


def test_zero_division():
    with pytest.raises(ZeroDivisionError):
        1 / 0

如果您需要访问实际的异常信息,您可以使用:

import pytest


def test_recursion_path():
    with pytest.raises(RuntimeError) as excinfo:
        def f():
            f()

        f()
        assert "maximun recursion" in str(excinfo.value)

excinfo 是一个 ExceptionInfo 实例,它是围绕引发的实际异常的包装器。经常使用的主要属性是 .type、.value 和 .traceback

您可以将 match 关键字参数传递给上下文管理器以测试正则表达式是否与异常的字符串表示匹配(类似于 unittest 的 TestCase.assertRaisesRegexp 方法):

import pytest


def myfunc():
    raise ValueError('Exception 123 raised')


def test_match():
    with pytest.raises(ValueError, match=r'.*123.*'):
        myfunc()

match 方法的 regexp 参数与 re.search 函数匹配,因此在上面的示例中 match='123' 也可以正常工作。

pytest.raises() 函数有另一种形式,您可以在其中传递一个函数,该函数将使用给定的 *args 和 **kwargs 执行,并断言引发了给定的异常:

pytest.raises(ExpectedException, func, *args, **kwargs)

报告器会在失败(例如无异常或错误异常)的情况下为您提供有用的输出。

请注意,也可以为 pytest.mark.xfail 指定一个“raises”参数,它检查测试是否以更具体的方式失败,而不仅仅是引发任何异常:

@pytest.mark.xfail(raises=IndexError)
def test_f():
    f()

使用 pytest.raises() 可能会更好地用于测试您自己的代码故意引发的异常的情况,而使用带有检查功能的 @pytest.mark.xfail 可能更适合记录未修复的错误(测试描述“应该”发生什么)或依赖项中的错误。

关于预期警告的断言

您可以使用 pytest.warns 检查代码是否引发了特定警告。

使用上下文相关的比较

pytest 有丰富的支持,可以在遇到比较时提供上下文相关的信息。例如:

# content of test_assert2.py


def test_set_comparison():
    set1 = set("1308")
    set2 = set("8035")
    assert set1 == set2

如果你运行这个模块

$ pytest test_assert2.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 1 item

test_assert2.py F                                                    [100%]

================================= FAILURES =================================
___________________________ test_set_comparison ____________________________

    def test_set_comparison():
        set1 = set("1308")
        set2 = set("8035")
>       assert set1 == set2
E       AssertionError: assert {'0', '1', '3', '8'} == {'0', '3', '5', '8'}
E         Extra items in the left set:
E         '1'
E         Extra items in the right set:
E         '5'
E         Use -v to get the full diff

test_assert2.py:6: AssertionError
========================= short test summary info ==========================
FAILED test_assert2.py::test_set_comparison - AssertionError: assert {'0'...
============================ 1 failed in 0.12s =============================

针对多种情况进行了特殊比较:

  1. 比较长字符串:显示上下文差异
  2. 比较长序列:第一个失败的索引
  3. 比较字典:不同的条目

有关更多示例,请参阅报告演示

为失败的断言定义你自己的解释

可以通过实现 pytest_assertrepr_compare 钩子来添加您自己的详细解释。

pytest_assertrepr_compare(config:?Config,?op:?str,?left:?object,?right:?object)?→?Optional[List[str]][source]

返回对失败断言表达式中的比较的解释。

返回 None 表示没有自定义解释,否则返回字符串列表。字符串将由换行符连接,但字符串中的任何换行符都将被转义。请注意,除了第一行之外的所有内容都会略微缩进,目的是让第一行成为摘要。

Parameters:

config?(_pytest.config.Config) – The pytest config object.

作为一个例子,考虑在 conftest.py 文件中添加以下钩子,它为 Foo 对象提供了另一种解释:

# content of conftest.py
from test_foocompare import Foo


def pytest_assertrepr_compare(op, left, right):
    if isinstance(left, Foo) and isinstance(right, Foo) and op == "==":
        return [
            "Comparing Foo instances:",
            "   vals: {} != {}".format(left.val, right.val),
        ]

现在,给定这个测试模块:

# content of test_foocompare.py
class Foo:
    def __init__(self, val):
        self.val = val

    def __eq__(self, other):
        return self.val == other.val


def test_compare():
    f1 = Foo(1)
    f2 = Foo(2)
    assert f1 == f2

您可以运行测试模块并获取 conftest 文件中定义的自定义输出:

$ pytest -q test_foocompare.py
F                                                                    [100%]
================================= FAILURES =================================
_______________________________ test_compare _______________________________

    def test_compare():
        f1 = Foo(1)
        f2 = Foo(2)
>       assert f1 == f2
E       assert Comparing Foo instances:
E            vals: 1 != 2

test_foocompare.py:12: AssertionError
========================= short test summary info ==========================
FAILED test_foocompare.py::test_compare - assert Comparing Foo instances:
1 failed in 0.12s

断言内省细节

通过在运行之前重写断言语句来报告有关失败断言的详细信息。重写的断言语句将内省信息放入断言失败消息中。pytest 仅重写由其测试收集过程直接发现的测试模块,因此不会重写支持模块中的断言,这些模块本身不是测试模块。

您可以通过在导入之前调用 register_assert_rewrite 来手动为导入的模块启用断言重写(在您的根 conftest.py 中这样做的好地方)。

有关更多信息,本杰明·彼得森 (Benjamin Peterson) 撰写了 pytest 新断言重写的幕后花絮

断言重写在磁盘的缓存文件

pytest 会将重写的模块写回磁盘以进行缓存。您可以通过将其添加到 conftest.py 文件的顶部来禁用此行为(例如,避免在大量移动文件的项目中留下陈旧的 .pyc 文件):

import sys

sys.dont_write_bytecode = True

请注意,您仍然可以获得断言自省的好处,唯一的变化是 .pyc 文件不会缓存在磁盘上。

此外,如果无法写入新的 .pyc 文件,即在只读文件系统或 zipfile 中,重写将默默地跳过缓存。

禁用断言重写

pytest 通过使用导入钩子编写新的 pyc 文件,在导入时重写测试模块。大多数情况下,这都是透明的。但是,如果您自己使用import机制,import钩子可能会干扰。

如果是这种情况,您有两种选择:

  • 通过将字符串 PYTEST_DONT_REWRITE 添加到其文档字符串来禁用特定模块的重写。
  • 使用 --assert=plain 禁用所有模块的重写。
  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:46:10  更:2021-08-21 15:46:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 20:32:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码