首页 > 资讯 > > 内容页

天天报道:自动化测试框架pytest教程

2023-04-23 15:37:03 博客园

快速入门

准备

推荐安装anaconda,默认带pytest


(资料图片)

# pip3 install pytest...$ pytest -h # 查看帮助...

第一个实例(通过)

def test_passing():    assert (1, 2, 3) == (1, 2, 3)

函数test_passing()为测试函数,因为它以test_开头,并且在名字以test_开头的文件中。assert 语句决定测试是通过还是失败。assert 是 Python 内置的关键字,如果 assert 后面的表达式是假的将引发 AssertionError 异常。在测试中引发的任何未捕获的异常都会导致测试失败。尽管任何类型的未捕获的异常都会导致测试失败,但传统上我们坚持用assert的AssertionError来决定测试的通过/失败。

$ pytest test_pass.py============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0rootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collected 1 itemtest_pass.py .                                                           [100%]============================== 1 passed in 0.08s ==============================

pass_test.py后的点表示一个测试运行并通过。 如果你需要更多信息,您可以使用-v或--verbose

$ pytest test_pass.py -v============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0 -- D:\ProgramData\Anaconda3\python.execachedir: .pytest_cacherootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collecting ... collected 1 itemtest_pass.py::test_passing PASSED                                        [100%]============================== 1 passed in 0.08s ==============================

在彩色终端,PASSED和底线是绿色的。

第二个实例(失败)

def test_failing():    assert (1, 2, 3) == (3, 2, 1)
$ pytest test_fail.py============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0rootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collected 1 itemtest_fail.py F                                                           [100%]================================== FAILURES ===================================________________________________ test_failing _________________________________    def test_failing():>       assert (1, 2, 3) == (3, 2, 1)E       assert (1, 2, 3) == (3, 2, 1)E         At index 0 diff: 1 != 3E         Use -v to get more difftest_fail.py:2: AssertionError=========================== short test summary info ===========================FAILED test_fail.py::test_failing - assert (1, 2, 3) == (3, 2, 1)============================== 1 failed in 0.14s ==============================

pytest准确地告诉我们失败:At index 0 diff: 1 != 3。如果你有一个彩色终端,大部分内容会以红色显示。这个额外的部分显示了测试失败的确切位置和相关代码,被称为回溯。

同样-v可以获取更多信息

$ pytest test_fail.py -v============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0 -- D:\ProgramData\Anaconda3\python.execachedir: .pytest_cacherootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collecting ... collected 1 itemtest_fail.py::test_failing FAILED                                        [100%]================================== FAILURES ===================================________________________________ test_failing _________________________________    def test_failing():>       assert (1, 2, 3) == (3, 2, 1)E       assert (1, 2, 3) == (3, 2, 1)E         At index 0 diff: 1 != 3E         Full diff:E         - (3, 2, 1)E         ?  ^     ^E         + (1, 2, 3)E         ?  ^     ^test_fail.py:2: AssertionError=========================== short test summary info ===========================FAILED test_fail.py::test_failing - assert (1, 2, 3) == (3, 2, 1)============================== 1 failed in 0.15s ==============================

更多运行方式

要运行pytest,你可以选择指定文件和目录。如果你不指定任何文件或目录,pytest将在当前工作目录和子目录中寻找测试。它寻找以test_开头或以_test结尾的.py文件。在ch1目录下,如果运行没有命令的pytest,你将运行两个文件的测试。

$ pytest --tb=no============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0rootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collected 2 itemstest_fail.py F                                                           [ 50%]test_pass.py .                                                           [100%]=========================== short test summary info ===========================FAILED test_fail.py::test_failing - assert (1, 2, 3) == (3, 2, 1)========================= 1 failed, 1 passed in 0.08s =========================

我还使用了 --tb=no 标志来关闭回溯,因为我们现在并不真正需要完整的输出。

我们也可以通过指定测试或列出目录名称来获得相同的测试集来运行。

$ pytest --tb=no test_pass.py test_fail.py============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0rootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collected 2 itemstest_pass.py .                                                           [ 50%]test_fail.py F                                                           [100%]=========================== short test summary info ===========================FAILED test_fail.py::test_failing - assert (1, 2, 3) == (3, 2, 1)========================= 1 failed, 1 passed in 0.09s =========================

我们也可以通过在文件名中加入::test_name来指定在测试文件中运行的测试函数。

$ pytest -v ch1/test_pass.py::test_passing============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0 -- D:\ProgramData\Anaconda3\python.execachedir: .pytest_cacherootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collecting ... collected 1 itemch1/test_pass.py::test_passing PASSED                                    [100%]============================== 1 passed in 0.08s ==============================

测试发现

pytest执行的部分,即pytest去寻找要运行的测试,被称为测试发现。pytest能够找到所有我们希望它运行的测试,因为我们根据pytest的命名规则给它们命名。

在没有参数的情况下,pytest会在你的当前目录和所有子目录中寻找测试文件,并运行它找到的测试代码。如果你给pytest文件名、目录名或列表,它就会在那里寻找,而不是在当前目录。在命令行中列出的每个目录都会被检查出测试代码,以及任何子目录。

下面是对命名规则的简要概述

如果你的测试以不同方式命名,有办法改变这些发现规则。我将在第8章,配置文件中介绍如何做到这一点。

测试结果

到目前为止,我们已经看到一个通过的测试和一个失败的测试。然而,通过和失败并不是唯一可能的结果。

下面是可能结果:

测试函数

简介

在本章中,你将学习如何在测试Python包的情况下编写测试函数。如果你用 pytest 来测试 Python 包以外的东西,本章的大部分内容仍然适用。

我们将为一个简单的任务跟踪命令行程序写测试,这个程序叫做 Cards。我们将研究如何在测试中使用 assert,测试如何处理意外的异常,以及如何测试预期的异常。

最终,我们会有很多的测试。因此,我们将研究如何将测试组织成类、模块和目录。

安装示例应用

我们编写的测试代码需要能够运行应用程序的代码。应用程序代码 "是我们正在验证的代码,它有很多名字。你可能会听到它被称为生产代码、应用程序、被测代码(CUT:code under test )、被测系统(SUT:system under test)、被测设备(DUT:device under test),我们将使用 "应用代码 "这个术语。

测试代码 "是我们为了测试应用代码而编写的代码。具有讽刺意味的是,"测试代码 "是相当明确的,除了 "测试代码 "之外,没有太多的名字。

在我们的例子中,Cards 项目就是应用程序代码。它是一个可安装的 Python 包,我们需要安装它以测试它。安装它也将允许我们在命令行上玩弄 Cards 项目。如果你要测试的代码不是可以安装的 Python 包,你就必须用其他方法让你的测试看到你的代码。(一些替代方法在第 12 章 测试脚本和应用程序中讨论。)

$ pip install cards_proj/Processing d:\code\pytest_quick\cards_proj  Installing build dependencies: started  Installing build dependencies: finished with status "done"  Getting requirements to build wheel: started  Getting requirements to build wheel: finished with status "done"  Preparing metadata (pyproject.toml): started  Preparing metadata (pyproject.toml): finished with status "done"Collecting typer==0.3.2  Downloading typer-0.3.2-py3-none-any.whl (21 kB)Collecting tinydb==4.5.1  Downloading tinydb-4.5.1-py3-none-any.whl (23 kB)Collecting rich==10.7.0  Downloading rich-10.7.0-py3-none-any.whl (209 kB)     ------------------------------------ 209.6/209.6 kB 706.8 kB/s eta 0:00:00Requirement already satisfied: colorama<0.5.0,>=0.4.0 in d:\programdata\anaconda3\lib\site-packages (from rich==10.7.0->cards==1.0.0) (0.4.5)Collecting commonmark<0.10.0,>=0.9.0  Downloading commonmark-0.9.1-py2.py3-none-any.whl (51 kB)     ---------------------------------------- 51.1/51.1 kB 1.3 MB/s eta 0:00:00Requirement already satisfied: pygments<3.0.0,>=2.6.0 in d:\programdata\anaconda3\lib\site-packages (from rich==10.7.0->cards==1.0.0) (2.11.2)Collecting click<7.2.0,>=7.1.1  Downloading click-7.1.2-py2.py3-none-any.whl (82 kB)     ---------------------------------------- 82.8/82.8 kB 1.5 MB/s eta 0:00:00Building wheels for collected packages: cards  Building wheel for cards (pyproject.toml): started  Building wheel for cards (pyproject.toml): finished with status "done"  Created wheel for cards: filename=cards-1.0.0-py3-none-any.whl size=5011 sha256=61c1601a2053682eeccbafcf120c2606604175b8730f7681ca5a0a521b83c6c5  Stored in directory: D:\Temp\pip-ephem-wheel-cache-5y22fhi5\wheels\0a\19\39\ed9dee4c4704cf05c72119386093ac231b9fe1c12faf5da0ccSuccessfully built cardsInstalling collected packages: commonmark, tinydb, rich, click, typer, cards  Attempting uninstall: click    Found existing installation: click 8.0.4    Uninstalling click-8.0.4:      Successfully uninstalled click-8.0.4ERROR: pip"s dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.black 22.6.0 requires click>=8.0.0, but you have click 7.1.2 which is incompatible.Successfully installed cards-1.0.0 click-7.1.2 commonmark-0.9.1 rich-10.7.0 tinydb-4.5.1 typer-0.3.2
$cards add "联系作者:钉钉、抖音或微信pythontesting" --owner Andrew$cards  ID   state   owner    summary ───────────────────────────────────────────────────────────────  1    todo    Andrew   联系作者:钉钉、抖音或微信pythontesting$cards add "抢火车票" --owner Bob$cards  ID   state   owner    summary ───────────────────────────────────────────────────────────────  1    todo    Andrew   联系作者:钉钉、抖音或微信pythontesting  2    todo    Bob      抢火车票$cards update 2 --owner Ted$cards  ID   state   owner    summary ───────────────────────────────────────────────────────────────  1    todo    Andrew   联系作者:钉钉、抖音或微信pythontesting  2    todo    Ted      抢火车票$cards start 1$cards finish 1$cards  ID   state   owner    summary ───────────────────────────────────────────────────────────────  1    done    Andrew   联系作者:钉钉、抖音或微信pythontesting  2    todo    Ted      抢火车票$cards add "testing" --owner Bob$cards  ID   state   owner    summary ───────────────────────────────────────────────────────────────  1    done    Andrew   联系作者:钉钉、抖音或微信pythontesting  2    todo    Ted      抢火车票  3    todo    Bob      testing$cards delete 3$cards  ID   state   owner    summary ───────────────────────────────────────────────────────────────  1    done    Andrew   联系作者:钉钉、抖音或微信pythontesting  2    todo    Ted      抢火车票

cards可以用添加、更新、开始、结束和删除等动作来操作,而运行cards会列出卡片。

很好。现在我们准备写一些测试了。

了解被测系统

Cards的源代码被分成三层。CLI、 API, 和 DB. CLI处理与用户的交互。CLI调用API,它处理应用程序的大部分逻辑。API调用DB层(数据库),用于保存和检索应用数据。我们将在《软件架构》中更多地了解卡片的结构。

有一个数据结构用来在ClI和API之间传递信息,这个数据类叫做Card。

@dataclassclass Card:    summary: str = None    owner: str = None    state: str = "todo"    id: int = field(default=None, compare=False)    @classmethod    def from_dict(cls, d):        return Card(**d)    def to_dict(self):        return asdict(self)

Data class在 3.7 版本中被添加到 Python 中,但它们对一些人来说可能仍然很陌生。卡片结构有三个字符串字段:摘要、所有者和状态,以及一个整数字段:ID。摘要、所有者和id字段默认为无。状态字段默认为 "todo"。id字段也使用字段方法来利用compare=False,这应该是告诉代码,当比较两个Card对象是否相等时,不要使用id字段。我们一定会测试这一点,以及其他方面。为了方便和清晰起见,还增加了几个方法:from_dict和to_dict,因为Card(**d)或dataclasses.asdict()不是很容易读。

当面对新的数据结构时,快速测试往往是很有帮助的,这样你就可以了解数据结构是如何工作的。所以,让我们从一些测试开始,验证我们对这个东西应该如何工作的理解。

ch2/test_card.py

from cards import Carddef test_field_access():    c = Card("something", "brian", "todo", 123)    assert c.summary == "something"    assert c.owner == "brian"    assert c.state == "todo"    assert c.id == 123def test_defaults():    c = Card()    assert c.summary is None    assert c.owner is None    assert c.state == "todo"    assert c.id is Nonedef test_equality():    c1 = Card("something", "brian", "todo", 123)    c2 = Card("something", "brian", "todo", 123)    assert c1 == c2def test_equality_with_diff_ids():    c1 = Card("something", "brian", "todo", 123)    c2 = Card("something", "brian", "todo", 4567)    assert c1 == c2def test_inequality():    c1 = Card("something", "brian", "todo", 123)    c2 = Card("completely different", "okken", "done", 123)    assert c1 != c2def test_from_dict():    c1 = Card("something", "brian", "todo", 123)    c2_dict = {        "summary": "something",        "owner": "brian",        "state": "todo",        "id": 123,    }    c2 = Card.from_dict(c2_dict)    assert c1 == c2def test_to_dict():    c1 = Card("something", "brian", "todo", 123)    c2 = c1.to_dict()    c2_expected = {        "summary": "something",        "owner": "brian",        "state": "todo",        "id": 123,    }    assert c2 == c2_expected
$ pytest test_card.py============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0rootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collected 7 itemstest_card.py .......                                                     [100%]============================== 7 passed in 0.14s ==============================

这些测试的重点是检查对架构的理解,并可能为其他人甚至为未来的我记录这些知识。这种检查我自己的理解的用法,以及真正把测试当作玩弄应用程序代码的小游乐场,是超级强大的,我认为如果更多的人从这种心态开始,他们会更喜欢测试。

还要注意的是,所有这些测试都使用普通的断言语句。

断言assert

当你写测试函数时,普通的Python assert语句是你沟通测试失败的主要工具。这在pytest中的简单性是非常好的。这也是促使很多开发者使用pytest而不是其他框架的原因。

如果你使用过任何其他测试框架,你可能已经看到了各种断言辅助函数。例如,下面是unittest的一些断言形式和断言辅助函数的列表。

在pytest中,你可以对任何表达式使用assert 。如果该表达式转换为bool的话,会评估为False,测试会失败。

pytest包括 "断言重写 "的功能,它可以拦截断言调用,并将其替换为可以告诉你更多关于断言失败原因的内容。让我们通过查看一个断言的失败来看看这种重写有多大帮助。

ch2/test_card_fail.py

def test_equality_fail():    c1 = Card("sit there", "brian")    c2 = Card("do something", "okken")    assert c1 == c2

这个测试会失败,但有趣的是追踪信息。

$ pytest test_card_fail.py============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0rootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collected 1 itemtest_card_fail.py F                                                      [100%]================================== FAILURES ===================================_____________________________ test_equality_fail ______________________________    def test_equality_fail():        c1 = Card("sit there", "brian")        c2 = Card("do something", "okken")>       assert c1 == c2E       AssertionError: assert Card(summary=...odo", id=None) == Card(summary=...odo", id=None)EE         Omitting 1 identical items, use -vv to showE         Differing attributes:E         ["summary", "owner"]EE         Drill down into differing attribute summary:E           summary: "sit there" != "do something"...EE         ...Full output truncated (8 lines hidden), use "-vv" to showtest_card_fail.py:7: AssertionError=========================== short test summary info ===========================FAILED test_card_fail.py::test_equality_fail - AssertionError: assert Card(su...============================== 1 failed in 0.22s ==============================

这是很大的信息量。对于每个失败的测试,失败的确切行被显示出来,并有一个 > 指向失败。E行显示了关于断言失败的额外信息,以帮助你找出出错的原因。

我故意在test_equality_fail()中放了两个不匹配,但在前面的代码中只显示了第一个。让我们按照错误信息中的建议,用-vv标志再试一下。

$ pytest -vv test_card_fail.py============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0 -- D:\ProgramData\Anaconda3\python.execachedir: .pytest_cacherootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collecting ... collected 1 itemtest_card_fail.py::test_equality_fail FAILED                             [100%]================================== FAILURES ===================================_____________________________ test_equality_fail ______________________________    def test_equality_fail():        c1 = Card("sit there", "brian")        c2 = Card("do something", "okken")>       assert c1 == c2E       AssertionError: assert Card(summary="sit there", owner="brian", state="todo", id=None) == Card(summary="do something", owner="okken", state="todo", id=None)EE         Matching attributes:E         ["state"]E         Differing attributes:E         ["summary", "owner"]EE         Drill down into differing attribute summary:E           summary: "sit there" != "do something"E           - do somethingE           + sit thereEE         Drill down into differing attribute owner:E           owner: "brian" != "okken"E           - okkenE           + briantest_card_fail.py:7: AssertionError=========================== short test summary info ===========================FAILED test_card_fail.py::test_equality_fail - AssertionError: assert Card(su...============================== 1 failed in 0.21s ==============================

pytest明确列出了哪些属性是匹配的,哪些是不匹配的,并强调了确切的不匹配。

在pytest.org网站上可以找到更多种类的断言语句,并有很好的跟踪调试信息。

断言失败是测试代码导致测试失败的主要方式。然而,这并不是唯一的方式。

通过pytest.fail()和异常失败用例

如果有任何未捕获的异常,测试就会失败。这可能发生在

虽然任何异常都可以使测试失败,但我更喜欢使用assert。在极少数情况下,如果assert不合适,可以使用pytest.fail()。

下面是使用pytest的fail()函数来明确地使测试失败的例子。

ch2/test_alt_fail.py

$ cat test_alt_fail.pyimport pytestfrom cards import Carddef test_with_fail():    c1 = Card("sit there", "brian")    c2 = Card("do something", "okken")    if c1 != c2:        pytest.fail("they don"t match")
$ pytest test_alt_fail.py============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0rootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collected 1 itemtest_alt_fail.py F                                                       [100%]================================== FAILURES ===================================_______________________________ test_with_fail ________________________________    def test_with_fail():        c1 = Card("sit there", "brian")        c2 = Card("do something", "okken")        if c1 != c2:>           pytest.fail("they don"t match")E           Failed: they don"t matchtest_alt_fail.py:9: Failed=========================== short test summary info ===========================FAILED test_alt_fail.py::test_with_fail - Failed: they don"t match============================== 1 failed in 0.21s ==============================

当调用pytest.fail()或直接引发异常时,我们不会得到pytest提供的奇妙的断言重写。然而,也有合理的时候使用pytest.fail(),比如在断言帮助器中。

编写断言助手函数

断言助手是用来包装复杂的断言检查的函数。举个例子,Cards数据类的设置是这样的:两张ID不同的卡片仍然会报告相等。如果我们想有更严格的检查,我们可以写一个叫assert_identical的辅助函数,像这样。

from cards import Cardimport pytestdef assert_identical(c1: Card, c2: Card):    __tracebackhide__ = True    assert c1 == c2    if c1.id != c2.id:        pytest.fail(f"id"s don"t match. {c1.id} != {c2.id}")def test_identical():    c1 = Card("foo", id=123)    c2 = Card("foo", id=123)    assert_identical(c1, c2)def test_identical_fail():    c1 = Card("foo", id=123)    c2 = Card("foo", id=456)    assert_identical(c1, c2)

assert_identical函数设置__tracebackhide__ = True。这是可选的。其效果是,失败的测试不会在回溯中包括这个函数。然后,正常的 assert c1 == c2 被用来检查除 ID 之外的所有内容是否相等。

最后,检查ID,如果它们不相等,就用pytest.fail()来拒绝测试,并希望有一个有用的信息。

让我们看看运行时是什么样子的。

$ pytest test_helper.py============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0rootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collected 2 itemstest_helper.py .F                                                        [100%]================================== FAILURES ===================================_____________________________ test_identical_fail _____________________________    def test_identical_fail():        c1 = Card("foo", id=123)        c2 = Card("foo", id=456)>       assert_identical(c1, c2)E       Failed: id"s don"t match. 123 != 456test_helper.py:21: Failed=========================== short test summary info ===========================FAILED test_helper.py::test_identical_fail - Failed: id"s don"t match. 123 !=...========================= 1 failed, 1 passed in 0.21s =========================

如果我们没有加入 tracebackhide= True,assert_identical 代码就会被包含在跟踪回溯中,在这种情况下,不会增加任何清晰度。我也可以使用 assert c1.id == c2.id, "id"s don"t match." 达到同样的效果,但我想展示一个使用 pytest.fail() 的例子。

注意,断言重写只适用于conftest.py文件和测试文件。

测试预期的异常

我们已经研究了任何异常如何导致测试失败。但是如果你正在测试的一段代码应该引发一个异常呢?你如何测试呢?

你可以使用 pytest.raises() 来测试预期的异常。

卡片API有CardsDB类,需要一个路径参数。如果我们不传入路径会发生什么?让我们来试试。

import cardsdef test_no_path_fail():    cards.CardsDB()
$ pytest --tb=short test_experiment.py============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0rootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collected 1 itemtest_experiment.py F                                                     [100%]================================== FAILURES ===================================______________________________ test_no_path_fail ______________________________test_experiment.py:5: in test_no_path_fail    cards.CardsDB()E   TypeError: __init__() missing 1 required positional argument: "db_path"=========================== short test summary info ===========================FAILED test_experiment.py::test_no_path_fail - TypeError: __init__() missing ...============================== 1 failed in 0.20s ==============================

这里我使用了 --tb=short 较短的回溯格式,因为我们不需要看到完整的回溯来发现哪个异常被引发。

TypeError异常是合理的,因为错误发生在试图初始化自定义的CardsDB类型时。我们可以写一个测试来确保这个异常被抛出,像这样。

import pytestimport cardsdef test_no_path_raises():    with pytest.raises(TypeError):        cards.CardsDB()def test_raises_with_info():    match_regex = "missing 1 .* positional argument"    with pytest.raises(TypeError, match=match_regex):        cards.CardsDB()def test_raises_with_info_alt():    with pytest.raises(TypeError) as exc_info:        cards.CardsDB()    expected = "missing 1 required positional argument"    assert expected in str(exc_info.value)
$ pytest test_exceptions.py============================= test session starts =============================platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0rootdir: D:\code\pytest_quick, configfile: pytest.iniplugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0collected 3 itemstest_exceptions.py ...                                                   [100%]============================== 3 passed in 0.15s ==============================

with pytest.raises(TypeError): 的下一个代码块中的任何内容都应该引发一个TypeError异常。如果没有产生异常,测试就会失败。如果测试引发了一个不同的异常,则失败。

我们刚刚在test_no_path_raises()中检查了异常的类型。我们还可以检查以确保消息是正确的,或者异常的任何其他方面,比如额外的参数。

匹配参数需要一个正则表达式并与异常信息相匹配。如果是一个自定义的异常,你也可以使用 exc_info 或任何其他的变量名来询问异常的额外参数。exc_info对象将是ExceptionInfo类型的。关于ExceptionInfo的完整参考,请参见pytest文档。

x 广告
最近更新

天天报道:自动化测试框架pytest教程

2023-04-23

冰与火之舞rush b_Rush b什么意思

2023-04-23

开封市中心医院:参观新院区建设 激励使命担当

2023-04-23

日本市长候选人街头演讲遭锁喉扑倒 基本情况讲解

2023-04-23

八部门:加快IPv6基础设施演进发展

2023-04-23

全球快讯:中国青年女科学家团队奖颁奖 陕西航天人获殊荣

2023-04-23

天天视点!秦皇岛社保缴费标准查询 2023秦皇岛社保个人需要交多少钱

2023-04-23

天天观速讯丨孕产妇安全营养全书

2023-04-23

梦想合伙人手游好玩吗 梦想合伙人手游玩法简介

2023-04-23

三极雄光今年一季度净利润约1171万元_今日视点

2023-04-23

每日头条!男子自修气功练憋气,意外练破肺!医生紧急提醒

2023-04-23

环球百事通!QQ音乐巅峰榜第一季度榜单:不出所料,这些歌手与单曲登榜

2023-04-23

下一波疫情高峰是否已在路上详细内容_天天播资讯

2023-04-23

世界关注:金融之力“贷”动南康家具“智”造

2023-04-23

当前热门:基于 Stream IO 软件的媒体摄取和播放平台

2023-04-23

北京:今天气温较低 请及时添加衣物

2023-04-23

日本农相向欧盟农业委员要求撤销食品进口限制-天天微头条

2023-04-23

有关于元旦的古诗词(有关于元旦的古诗)

2023-04-23

当前快报:嘉实海外基金净值今天(嘉实海外基金今日净值查询)

2023-04-23

【攻略】火山的女儿-父亲以身作则|今日关注

2023-04-23

世界速递!天子寻龙粤语解说_天子寻龙粤语

2023-04-23

什么是纯循环小数呢_什么是纯循环小数

2023-04-23

顺义区邀您打卡21家“特色书店”-环球百事通

2023-04-23

【天天时快讯】李斌:蔚来不卷价格卷价值 今年望变成“蔚两万”

2023-04-23

当前速递!九年级上册语文笔记第一课_九年级上册语文笔记

2023-04-23

全民K歌怎么邀请好友到好友歌房 全民k歌怎么邀好友唱歌

2023-04-23

土建造价员证_中建造价员证

2023-04-23

【全球聚看点】全能永久免vip无限次数人工智能ai无痕图片短视频去水印软件免费版

2023-04-23

正方体怎么画简单_正方体怎么画_世界速讯

2023-04-23

环球外汇网_关于环球外汇网介绍 世界观察

2023-04-23

地藏菩萨本愿经诵唱诵版45分钟视频(地藏菩萨本愿经诵唱)|焦点信息

2023-04-23

信息:收集大数的信息四年级手抄报_收集大数的信息

2023-04-23

当前简讯:北京国际电影节举办开幕式红毯 代乐乐随《川流不“熄”》剧组亮相

2023-04-23

当前快讯:月子餐42天食谱表格_月子食谱42天表格

2023-04-22

当前播报:女人保养方法_女人怎么保养

2023-04-22

独立报:波切蒂诺离切尔西越来越近,纳帅对去热刺态度开放

2023-04-22

焦点精选!中国男足新阵容展望:4老将掉队,6大归化回归,门将席卷留洋风暴

2023-04-22

【世界新视野】康维他

2023-04-22

如何捣碎大蒜-今日聚焦

2023-04-22

正规借条格式范本_借据格式范本

2023-04-22

全球热点评!各地多措并举加强森林草原火灾防控

2023-04-22

焦点热议:民生控股:公司目前注册地在青岛崂山区。关于您第二个问题,公司并未知悉

2023-04-22

当前热讯:手动挡汽车起步步骤讲解_手动挡汽车起步步骤

2023-04-22

湘乡市气象局发布冰雹橙色预警【Ⅱ级/严重】-焦点热文

2023-04-22

环球即时看!康师傅冰红茶_康师傅冰红茶批发

2023-04-22

全球实时:“五一”假期 沈阳铁路加开多趟热门方向旅客列车

2023-04-22

近150家央企子企业落户,利好重仓环京房企

2023-04-22

长葛市属于哪个市管辖_长葛市属于哪个市

2023-04-22

天天观察:特斯拉在300万美元索赔案胜诉,洛杉矶法院裁定辅助驾驶系统Autopilot未失去安全性能

2023-04-22

格力地产2022年归母净亏损26.84亿 房地产业务毛利率27.56%

2023-04-22

南宁在景区举办千人相亲大会,重现“三月三”以歌传情盛景 全球微速讯

2023-04-22

派出所所长怒吼:“给她道歉!”

2023-04-22

马斯克确认:会“亲自”为名人支付推特订阅服务_全球新消息

2023-04-22

每日速讯:筲箕拼音_筲

2023-04-22

全球资讯:直播招募:AIGC竞速正当时,是谁快人一步?|量子位·视点

2023-04-22

王东声丨提笔先须问性情

2023-04-22

Africell在安哥拉推出移动支付平台,旨在提升安哥拉移动金融普及率

2023-04-22

日媒:福岛第一核电站核污染水排海可能于7月开始实施

2023-04-22

缅甸传出两则关于昂山素季的消息-天天看热讯

2023-04-22

多举措 做好新形势下员工工作|世界视点

2023-04-22

天天新消息丨高分机甲主题动画片《动车侠》登陆福建少儿频道播出

2023-04-22

世界视点!日输气能力达6810万立方米!双台子储气库双向输气管道工程成功投产

2023-04-22

环球快看:找到了!男子江边离奇失踪7天,竟然还活着!

2023-04-22

环球速递!蓝厅论坛|对话布鲁金斯李成:“气球事件”受到美国利益集团的左右

2023-04-22

微资讯!新华医疗04月21日被沪股通减持9.62万股

2023-04-22

环球新消息丨地域文化在先秦法家研究中的重要性

2023-04-22

【世界新要闻】住总集团:2023年一季度实现营业收入110亿元

2023-04-22

定州市图书馆馆长荐读这本古代劝善书_今热点

2023-04-22

休斯顿火箭队 休斯顿火箭队最新交易-全球快看点

2023-04-22

世界观焦点:解放军总医院第七医学中心实施首例腔镜下甲状旁腺肿瘤切除术

2023-04-22

架设“GOIP”设备帮助境外分子搞诈骗?常宁警方:抓! 热闻

2023-04-22

【全球独家】华工科技:公司在半导体领域开发了激光晶圆检测设备等产品

2023-04-22

为什么炒出来柚子糖是软绵绵的?

2023-04-22

@四川人 川航“五一”前后将恢复4条国内外航线|视焦点讯

2023-04-22

焦点播报:中新观陇“新闻+”作品联展第一站:酒泉职工观后感“让民众都看得懂”

2023-04-22

直播间“贩卖”小哥哥:有人看没人买

2023-04-22

义翘神州(301047)2022年年报简析:净利润减57.9%,三费占比上升明显_天天快播

2023-04-22

1英镑是多少人民币 今天_1英镑是多少人民币_天天速读

2023-04-22

央行:83个城市已下调首套房贷利率下限

2023-04-22

台商创二代王伯扬扎根大陆:喜欢惠州的人情味 全球百事通

2023-04-22

三方签约共建华侨大学国家语言服务出口基地

2023-04-22

世界观天下!长城证券:一季度净利润同比扭亏为盈

2023-04-22

热文:今日草莓什么季节成熟的水果_草莓什么季节成熟

2023-04-22

快报:德乙提醒:达姆斯塔近10主不败+7胜 造角球能力强

2023-04-22

男子超范围滥伐林木蓄积近80立方米 法院发出“低碳行为令”补种黄柏500株

2023-04-22

4月21日基金净值:银华心兴三年持有混合A最新净值0.8419,跌1.58%

2023-04-22

三部门印发《绿色数据中心政府采购需求标准(试行)》

2023-04-22

花之舞钢琴谱完整版_花之舞钢琴原版

2023-04-22

港股异动 | 乐华娱乐(02306)大涨逾11% 旗下4名练习生在韩国C位出道-热讯

2023-04-22

天天热推荐:短期汉语系列教材:游河南

2023-04-22

西安遭遇今春最强沙尘 PM10浓度值破千 环球要闻

2023-04-22

电力企业工程建设工作计划(推荐6篇) 微动态

2023-04-22

环球最新:国家防总办公室、应急管理部会同相关省份全力防范应对强降雨过程

2023-04-22

优酷会员免费三天_全球即时看

2023-04-21

【 川网观大运】大运会城市志愿服务首个地铁示范(共享)小站亮相 滚动

2023-04-21

乌克兰首都上空现巨大光球,是美国卫星坠落还是 UFO?

2023-04-21

快看:精子活力低可以怀孕吗_精子活力低是什么原因造成的

2023-04-21

如何用电脑发网络传真?电脑如何发送电子邮件?|天天观天下

2023-04-21

当前热讯:是否存在整数abc满足_9/8_是否存在整数m

2023-04-21

【全球热闻】各地开工提速 “5G项目云”助力等数智化产品加速复苏

2023-04-21

智能混凝土结构体系的物性参数识别研究_对于智能混凝土结构体系的物性参数识别研究简单介绍

2023-04-21

俄军战机会倒霉吗,美国对乌提供“爱国者”,乌军再也不怕空袭?-天天热议

2023-04-21

欧洲现代建筑解析 环球焦点

2023-04-21

话剧《半个月亮掉下来》将于5月亮相-短讯

2023-04-21

康师傅控股:2022年公司股东应占溢利同比衰退30.77%至26.32亿元 速讯

2023-04-21

亲嘴鱼为什么会亲嘴 亲嘴鱼

2023-04-21

大宗交易:兰州银行成交160.02万元,折价7.74%(04-21) 全球资讯

2023-04-21

“中国石油开放日”有看头

2023-04-21

今日关注:土木工程的就业方向及就业前景_土木工程就业方向哪些

2023-04-21

罗马、尤文图斯晋级欧联杯四强,欧洲赛场意甲球队横行-天天观点

2023-04-21

环球精选!一季度工业和信息化发展实现平稳开局

2023-04-21

【建设平安云梦】曾店镇:开展消防安全培训 提升民警辅消防处置能力

2023-04-21

焦点信息:勤上股份:控股股东筹划控制权变更事项,公司股票停牌

2023-04-21

上海车展林肯Z太卷了,颜值太吸睛

2023-04-21

晓程科技:暂无CPO技术储备|热议

2023-04-21

《布莱泽奥特曼》7月8日开播 田口清隆执导_全球速看料

2023-04-21

8k纸和a4纸对比多大图片_8k纸尺寸和a4

2023-04-21

北京延庆区:鲜食玉米种植满满“科技味” 环球快播报

2023-04-21

每日消息!2023年信贷及社融将保持平稳增长

2023-04-21

西安有了自己的“城市HR” 西安人才集团揭牌运营 全球微资讯

2023-04-21

每日速递:成都大运会期间将开展一系列青年交流活动

2023-04-21

信息:最高18℃+小到中雨+局地中到大雪!河北最新天气预报、限行提示、高速路况请查收→

2023-04-21

视焦点讯!屡战屡败的快时尚生意,怎么就被电商平台盯上了?

2023-04-21

中原期货:IF回调蓄势|全球视点

2023-04-21

环球热议:登上舞台赵奕欢_登上舞台

2023-04-21

焦点播报:PS游戏同性浪漫关系越来越多?博主发文反驳

2023-04-21

法兴银行:美国4月税收下降将使债务大限提前到来

2023-04-21

4月21日起,芜湖市11条公交线路运营方案调整 全球快报

2023-04-21

世界微速讯:一季度全省农村建设品质提升超序时推进

2023-04-21

西凤酒文化研讨暨专家聘用仪式举行

2023-04-21

中国专家参加世界卫生组织成员国线上信息通报会 全球快消息

2023-04-21

兴文:“四季村晚”春季展示、“大地欢歌”乡村文化活动年、苗族花山节同步启动

2023-04-21

农业农村部:开展农村改厕“提质年”工作 全球滚动

2023-04-21

滕哈赫:德赫亚?他是英超零封最多门将,这说明他很有能力

2023-04-21

爆雷!千亿巨头突然亏损

2023-04-21

京多安:渴望明年随队参加主场欧洲杯 3-0拜仁还只是对决的半场

2023-04-21

每日资讯:绿能慧充(600212)4月20日主力资金净卖出5904.79万元

2023-04-21

轿车被恶意别车S形行驶10公里

2023-04-21

关于教师节的名句短句 环球最新

2023-04-21

南宁大明山将举办系列主题活动 助推旅游市场升温

2023-04-21

建设国家知识产权强市示范城市,长沙强劲开局|天天速递

2023-04-21

如何缩水氨纶 前沿热点

2023-04-21

环球微速讯:家用洗碗机洗碗要多久

2023-04-21

“中国体育彩票杯”2022年北京市青少年足球俱乐部联赛圆满落幕

2023-04-21

全球焦点!高效对接 通达全球!广交会第五天 人气持续氛围热烈

2023-04-21

墙面用什么材料装修最好|天天热闻

2023-04-21

检察机关依法分别对宇方成、高泽彬、李建飞提起公诉|焦点要闻

2023-04-21

使用AI预测建筑能耗和温室气体排放预测

2023-04-21

微粒贷网贷逾期30年不还会影响征信吗

2023-04-21

今日快讯:搞不清楚了!郭沫若究竟是大师?还是浪得虚名之辈?

2023-04-21

环球实时:海报时评丨黄河大集:一“集”连“九曲”,打造文化创新共同体

2023-04-21

热消息:归创通桥-B(02190)与广东海思卡尔医疗科技有限公司达成战略合作

2023-04-21

【世界新要闻】2023年第16周湖南生产资料市场价格以跌为主

2023-04-21

4月20日基金净值:工银聚润6个月持有混合A最新净值0.9857,涨0.06%|快看

2023-04-21

成都高新区印悦府翠园1、2、5栋人才公寓项目租售公告-天天热推荐

2023-04-21

国家体育总局授权腾讯等组建杭州亚运会电竞国家集训队_独家

2023-04-21

全球焦点!深圳取消二手房参考价?银行说“没见到文件”,中介称“已经实行”

2023-04-21

云上履职平台解决民生“微实事”_天天热头条

2023-04-21

中国轨道交通装备收获拉美市场好评 交通轨道设备行业市场分析2023

2023-04-20

电影《长空之王》发布“燃”版预告 大仰角穿云刺激音爆声震撼 头条焦点

2023-04-20

巴比食品:一季度净利4103.2万元 同比增2724.36%

2023-04-20

高速公路大气能见度监测、预报方法研究_关于高速公路大气能见度监测、预报方法研究简述

2023-04-20

每日简讯:阿胶糕天天吃有用吗?

2023-04-20

权威发布|省商务厅:以实施“2023消费提振年”为主战场,千方百计激发消费潜力-全球播资讯

2023-04-20

2023年武汉夏天几月份开始(武汉的夏天一般持续多少天)

2023-04-20

全球热点评!2023初级护师考试考点回顾:第一所护士学校的时间

2023-04-20

原神3.6深渊使用率一览

2023-04-20

算力彻底暴发!葛卫东操盘这只暴赚超30亿,5万亿“中东富豪”也出手,算力的超级行情要来了 世界聚焦

2023-04-20

浏览器配置异常 浏览器配置总是异常

2023-04-20

意财长称意大利可成为连接北非地区的能源枢纽

2023-04-20

全球即时看!汽车打“飞的” 杭州空港口岸首次出口新能源整车

2023-04-20

每日消息!2023版8克熊猫金币价格(2023年04月20日)

2023-04-20

教育部公布新一批普通高等学校本科专业备案和审批结果 新增专业21种 今日精选

2023-04-20

全球热头条丨红星发展: 红星发展计提减值准备公告

2023-04-20

每日简讯:希磁科技: 从安徽蚌埠走出的龙头企业

2023-04-20

马上评|“一口价黄金”营销,别忘记了“诚信是金”_环球报资讯

2023-04-20

天天快播:4月22日中超上海上港vs深圳队比赛时间+观赛指南

2023-04-20

世界热点!保定汽车抵押贷款可以用于哪些方面?

2023-04-20

东方铁塔2022年度净利同比增104.12% 拟10派4.1元

2023-04-20

每日信息:电脑桌面图标有蓝色的阴影怎么办_电脑桌面图标有蓝色阴影

2023-04-20

【世界时快讯】4499元!Redmi X 85英寸电视上市:120Hz高刷、3+32GB大存储

2023-04-20

灵活就业医保和城乡居民医保哪个好,到底该怎么选择?

2023-04-20

中小银行存款利率集体“补降” 未来或进一步下行

2023-04-20

微信附近人打招呼过期怎么加回来(微信附近人打招呼是直接加好友吗) 热门

2023-04-20

打疫苗后发烧怎么办崔玉涛_打疫苗后发烧怎么办_环球微头条

2023-04-20

热点!支付一年房租计入什么科目_支付一年房租会计分录

2023-04-20

全球动态:8亿年的原始生物化石!在安徽被发现了

2023-04-20

今日报丨7旬老人为保护孙子砍伤酒后闹事者获刑,申诉近两年检方撤诉获法院准许

2023-04-20

合肥市瑶海区孙何小郢复建点项目首栋楼封顶

2023-04-20

数据飞轮转起来:火山引擎发布多款数据产品

2023-04-20

百事通!彩金贵妃醉酒金币价格今天多少一克(2023年04月20日)

2023-04-20

茂县“三强化”提升干部监督合力|环球今日讯

2023-04-20

dwg文件怎么打开最好_dwg文件怎么打开

2023-04-20

简单的教师节贺卡怎么做_教师节贺卡制作方法_报道

2023-04-20

联合光电:4月19日融券卖出5.56万股,融资融券余额1.08亿元

2023-04-20

肖战和杨紫,这是什么情况?

2023-04-20

2023年4月12日至2023年4月18日环渤海动力煤价格指数环比持平 环球聚焦

2023-04-20

焦点热文:传统滋补营养品委托生产协议_传统滋补

2023-04-20

关于中国剪纸的资料_剪纸的资料

2023-04-20

环球快播:矿山巡检不再难智能机器人可代劳

2023-04-19