《pytest测试实战》-- Brian Okken
1|0一、pytest 入门
这是一个测试用例
执行
结果
这是第二个测试用例
运行后结果
1|11.1 资源获取
pytest的官方文档地址
pytest通过PyPI(Python官方包管理索引)分发托管:
建议使用vritualenv来使用
1|21.2 运行pytest
在没有其他参数的情况下,pytest会递归遍历每个目录及其子目录。
举一个例子,我们创建一个tasks子目录,并且创建以下测试文件:
下面演示下_asdict() 函数和 _replace() 函数的功能:
运行时
如果不指定,pytest会搜索当前目录及子目录中以test_开头或者以_test结尾的测试函数
我们把 pytest 搜索测试文件和测试用例的过程称为测试搜索(test discovery)。只要遵守命名规则,就能自动搜索。以下是几条主要的命名规则
- 测试文件应当命名为 test_<something>.py 或者 <something_test.py>
- 测试函数、测试类方法应当命名为teet_<something>
- 测试类应当命名为 Test<Something>
运行单个文件时的控制台信息
pytest为每段测试会话(session)做了明确的分隔,一段会话就是pytest的一次调用
运行平台和版本
rootdir(当前起始目录)是pytest搜索测试代码时最常使用的目录,inifile用于列举配置文件(这里没有定义),文件名可能是pytest.ini、tox.ini或者setup.cfg
搜索范围内找到两个测试条目
表示测试文件及结果。点号表示通过。Failure(失败)、error(异常)、skip(跳过)、xfail(预期失败)、xpass(预期失败但通过)会被分别标记为F、E、s、x、X,使用 -v 或者 --verbose 可以看到更多细节
表示测试通过或者失败等条目的数量以及这段会话耗费的时间,如果存在未通过的测试用例,则会根据未通过的类型列举数量。
以下是可能出现的类型:
PASSED(.):测试通过
FAILED(F):测试失败(也有可能是XPASS状态与strict选项冲突造成的失败,见后文)
SKIPPED(s):测试未被执行。指定测试跳过执行,可以将测试标记为@pytest.mark.skip(),或者使用@pytest.mark.skipif()指定跳过测试的条件
xfail(x):预期测试失败,并且确实失败。使用@pytest.mark.xfail()指定你认为会失败的测试用例。
XPASS(X):预期测试失败,但实际上运行通过,不符合预期。
ERROR(E):测试用例之外的代码触发了异常,可能由 fixture 引起,也可能由 hook 函数引起
1|31.3 运行单个测试用例
可以直接在指定文件后添加 ::test_name
1|41.4 使用命令行选项
--collect-only选项
使用 --collect-only 选项可以展示在给定的配置下哪些测试用例会被运行。
--collect-only选项可以让你非常方便地在测试运行之前,检查选中的测试用例是否符合预期。
-k 选项
-k 选项允许你使用表达式指定希望运行的测试用例。
假设希望选中 test_asdict() 和 test_defaults(),name可以使用 --collect-only 验证:
-m选项
标记(marker)用于标记测试并分组。
使用什么标记名由你自己决定,比如 @pytest.mark.mark1 或者 @pytest.mark.mark2
此时运行
使用 -m 选项可以用表达式指定多个标记名。
使用 -m "mark1 and mark2" 可以同时选中带有这两个标记的所有测试用例。
使用 -m "mark1 and not mark2" 则会选中带有mark1的测试用例,同时过滤掉带有mark2 的测试用例。
使用 -m "mark1 or mark2" 同时选中带有 mark1 或者 mark2 的所有测试用例。
-x 选项(小写)
正常情况下,如果有运行失败的用例,pytest 会标记为失败,但是会继续运行下一个测试用例。
如果我们希望遇到失败时立即停止整个会话,这时 -x 选项就派上用场了。
如果没有 -x 选项,那么6个测试都会被执行,去掉 -x 再运行一次,并且使用 --tb=no 选项关闭错误信息回溯。
--maxfail=num
-x 选项的特点是,一旦遇到测试失败,就会全局停止。
使用 --maxfail 选项,明确指定可以失败几次。
-s 与 --capture=method
-s选项允许终端在测试运行时输出某些结果(比如print),包括任何符合标准的的输出流信息。
-s 等价于 --capture=no
--lf(--last-failed)选项
当一个或多个测试失败时,我们常常希望能够定位到最后一个失败的测试用例重新运行,这时候可以使用 --lf 选项
至于上一个失败的测试用例,pytest框架会自动记录
--ff(--failed-first)选项
--ff(--failed-first)选项与 --last-failed选项的作用基本相同,不同之处在于 --ff 会运行完剩余的测试用例。
-v(--verbose)选项
最明显的区别就是每个文件中的每个测试用例都占一行(先前是每个文件占一行)
-q(--quiet)选项
该选项的作用与 -v/--verbose的相反,它会简化输出信息,只保留最核心的内容。
-l(--showlocals)选项
使用 -l 选项,失败测试用例由于被堆栈追踪,所以局部变量及其值都会显示出来。
assert 触发测试失败之后,代码片段下方显示的是本地变量 t_after、t_before、t_expected详细的值。标红处显示。
--tb=style选项
--tb=style选项决定捕捉到失败时输出信息的显示方式。某个测试用例失败后,pytest会列举出失败信息,包括失败出现在哪一行、是什么失败、怎么失败的,此过程我们称之为“信息回溯”。
常用的三种模式:
short 模式仅输出 assert的一行以及系统判定内容(不显示上下文);
line 模式只使用一行输出显示所有的错误信息
no 模式则直接屏蔽全部回溯信息
还有三种可选模式:
--tb=long 输出最为详尽的回溯信息
--tb=auto 是默认值,如果有多个测试用例失败,仅打印第一个和最后一个用例的回溯信息(格式与long模式的一致)
--tb=native 只输出Python标准库的回溯信息,不显示额外信息
--durations=N选项
--duration=N 选项可以加快测试节奏。它不关心测试时如何运行运行的,只统计测试过程中哪几个阶段是最慢的(包括每个测试用例的call、setup、teardown过程)。
使用--duration=0,则会将所有阶段按耗时长短排序后显示。
--version 选项
使用 --version 可以显示当前的 pytest 版本及安装目录
-h(--help)选项
使用 -h 选项可以获得:
基本用法:pytest [options] [file_or_dir] [file_or_dir] [...]
命令行选项及其用法,包括新添加的插件的选项及其用法
可用于ini配置文件中的选项
影响pytest行为的环境变量
使用 pytest --markers 时的可用 marker 列表
使用 pytest --fixtures 时的可用 fixture 列表
2|0二、编写测试函数
2|12.1 目录结构
Tasks项目的文件结构:
2|22.2 使用 assert 声明
pytest有一个重要功能是可以重写 assert 关键字。pytest 会截断对原生 assert 的调用,替换为 pytest 定义的assert,从而提供更多的失败信息和细节。
每个失败的测试用例在行首都用一个 > 号来标识。以 E 开头的行时 pytest 提供的额外判断信息,用于帮组我们了解异常的具体情况。
2|32.3 预期异常
测试异常的格式 with pytest.raises(<expected exception>)
测试用例 test_add_raises() 中有 with pytest.raises(TypeError)声明,意味着无论with中的内容是什么,都至少会发生TypeError异常。如果测试通过,说明确实发生了我们预期 TypeError 异常:如果抛出的是其他类型的异常,则与我们所预期的不一致,说明测试失败。
上面的测试中只检验了传参数据的 “类型异常”,换可以检验 “值异常”。为校验异常信息是否符合预期,可以通过增加 as excinfo 语句得到异常消息的值,再进行比对。
2|42.4 测试函数的标记
pytest 允许使用 marker 对测试函数做标记。
一个测试函数可以有多个 marker,一个 marker 也可以用来标记多个测试函数。
带有相同 marker 的测试即使存放在不同的文件下,也会被一起执行。
可以通过以下命令运行
-m 后面也可以加表达式,可以在标记之间添加 add、or、not 关键字
警告信息消除,mark标记时会warn,可以在conftest里面添加
2|52.5 跳过测试
skip 和 skipif 允许你跳过不希望运行的测试。
skipif() 的判断条件可以使任何Python 表达式,这里比对的是包版本。
如果运行的时候要看到跳过的原因,可以使用 -rs
-r 选项
-r
选项可以在执行结束后,打印一个简短的总结报告。在执行的测试用例很多时,可以让你对结果有个清晰的了解-r
选项后面要紧接以下的一个参数,用于过滤显示测试用例的结果。
以下是所有有效的字符参数:
- f:失败的
- E:出错的
- s:跳过执行的
- x:跳过执行,并标记为xfailed的
- X:跳过执行,并标记为xpassed的
- p:测试通过的
- P:测试通过,并且有输出信息的;即用例中有
print
等 - a:除了测试通过的,其他所有的;即除了
p
和P
的 - A:所有的
上述字符参数可以叠加使用,例如:我们期望过滤出失败的和未执行的:
2|62.6 标记预期会失败的测试
使用 skip 和 skipif 标记,测试会直接跳过,而不会被执行。使用 xfail 标记,则告诉pytest运行此测试,但我们预期它会失败。
2|72.7 运行测试子集
单个目录
运行单个目录下的所有测试,以目录作为 pytest 的参数即可。
单个测试文件/模块
运行单个文件里的全部测试,以路径名加文件名作为 pytest 参数即可。
单个测试函数
运行单个测试函数,只需要在文件名后面添加 :: 符号和函数号
单个测试类
测试类用于将某些相似的测试函数组合在一起。
要运行该类,可以在文件名后面加上 :: 符号和类名(与运行单个测试函数类似)
单个测试类中的测试方法
如果不希望运行测试类中的所有测试,只想指定运行其中一个,一样可以在文件名后面添加 :: 符号和方法名。
用测试名划分测试集合
-k 选项允许用一个表达式指定需要运行的测试,该表达式可以匹配测试名(或其子串)。
表达式中可以包含and 、or 、not
运行所有名字中包含 _raises 的测试
如果要跳过 test_delete_raises() 的执行,则可以使用 and 和 not
2|8 2.8 参数化测试
有时候仅仅使用一组数据是无法充分测试函数功能的,参数化测试允许传递多组数据。
@pytest.mark.parametrize() 的第一个参数是用逗号分隔的字符串列表;第二个参数是一个值列表。
pytest会轮流对每个task做测试,并分别报告每一个测试用例的结果。
以下是 多组键值对情况
执行如下:
如有以下的参数化测试用例
可见可读性非常差
为了改善可读性,我们为parametrize()引入一个额外参数ids,使列表中的每一个元素都被表示。ids 是一个字符串列表,它和数据对象列表的长度保持一致。由于给数据集分配了一个变量 tasks_to_try,所以可以通过他生成ids。
自定义测试标识能够被 pytest 识别
@pytest.mark.parametrize() 装饰器也可以给测试类加上,在这种情况下,该数据集会被传递给该类的所有类方法。
在给@pytest.mark.parametrize() 装饰器传入列表参数时,还可以在参数值旁边定义一个 id 来做标识,语法是 pytest.param(<value>,id="something")
标识也能够被识别
参数组合
方法作为参数名
3|0三、pytest fixture
fixture 是在测试函数运行前后,由pytest执行的外壳函数。
简单实例
测试用例 test_some_data() 的参数列表中包含一个 fixture名 some_data,pytest 会以该名称搜索 fixture(可见命名在pytest 中是非常重要的。)
pytest 会优先搜索该测试所在的模块,然后搜索 conftest.py
3|13.1 通过 conftest.py 共享 fixture
fixture 可以放在单独的测试文件里。此时只有这个测试文件能够使用相关的fixture。
如果希望多个测试文件共享 fixture,可以在某个公共目录下新建一个 conftest.py 文件,将 fixture 放在其中。(作用域根据所放的文件夹决定,最上层文件夹的话整个项目共用,子文件夹的话,子文件夹里面的测试共用。)
尽管 conftest.py 是Python 模块,但它不能被测试文件导入。import conftest 的用法是不允许出现的。conftest.py 被 pytest 视作一个本地插件库。可以把 tests/conftest.py 看成一是一个供 tests 目录下所有测试使用的 fixture仓库。
3|23.2 使用 fixture 执行配置及销毁逻辑
fixture 函数会在测试函数之前运行,但如果 fixture 函数包含 yield,那么系统会在 yield 处停止,转而运行测试函数,等测试函数执行完毕后再回到 fixture,继续执行 yield 之后的代码。
可以将 yield 之前的代码视为 配置(setup)过程,将yield 之后的代码视为清理(teardown)过程。
无论测试过程中发生了说明,yield之后的代码都会被执行。
3|33.3 使用 --setup-show 回溯 fixture 的执行过程
直接运行测试,则不会看到fisture的执行过程。
如果希望看到测试过程中执行的是什么,以及执行的先后顺序。pytest 提供的 --setup-show 选项可以实现这个功能。
fixture 名称前面的F 和S代表的是fixture的作用范围,F代表函数级别的作用范围。S代表会话级别的作用范围。
3|43.4 使用 fixture 传递测试数据
fixture 非常适合存放测试数据,并且它可以返回任何数据。
yeild 返回数据
明显23不等于32,所以会失败。
pytest 给出了具体引起 assert 异常的函数参数值。fixture 作为测试函数的参数,也会被堆栈跟踪并纳入测试报告。
假设assert 异常(或任何类型的异常)就发生在fixture,会发生什么?
在fixture 中,42 不等于 43,断言错误。pytest运行时,如下:
可以看到 执行结果是 ERROR 而不是 FAIL。
这个区分很清楚,如果测试结果为 fail,用户就知道失败是发生在核心测试函数内,而不是发生在测试依赖的 fixture。
3|53.5 使用多个 fixture
fixture互相调用
用例中传入多个fixture
3|63.6 指定 fixture 作用范围
fixture 包含一个叫 scope(作用范围)的可选参数,用于控制 fixture 执行配置和销毁逻辑的频率。@pytest.fixture() 的 scope 参数有四个待选值:
- function
- class
- module
- session(默认值)
以下是对各个 scope 的概述
scope=“function”
函数级别的 fixture 每个测试函数只需要运行一次。配置代码在测试用例运行之前运行,销毁代码在测试用例运行之后运行。是默认值
scope=“class”
类级别的fixture 每个测试类只需要运行一次,无论测试类里面有多少类方法都可以共享这个fixture
scope="module"
模块级别的fixture每个模块只需要运行一次,无论模块里有多少个测试函数、类方法或其他fixture 都可以共享这个fixture
scope=“session”
会话级别的 fixture 每次会话只需要运行一次。一次 pytest 会话中所有测试函数、方法都可以共享这个 fixture。
执行结果
使用 --setup-show 命令行选项观察每个 fixture 被调用的次数,以及在各自作用范围下执行配置、销毁逻辑的顺序。
F 代表函数级别,S 代表会话级别,C 代表类级别,M 代表模块级别
fixture 只能使用同级别的fixture,或比自己级别更高的fixture。
3|73.7 使用 usefixtures 指定fixture
使用 usefixtures 和在测试方法中添加 fixture 参数,二者大体上是差不多的。区别之一在于只有后者才能够使用fixture的返回值。
3|83.8 为常用 fixture 添加 autouse 选项
之前用到的 fixture 都是根据测试本身来命名的(或者针对示例的测试类使用 usefixtures)。我们可以通过制定 autouse=True选项,使作用域内的测试函数都自动运行 fixture
下面是一个比较生硬的例子
3|93.9 为 fixture 重命名
3|103.10 fixture 的参数化
fixture 参数列表中的request 也是 pytest 内建的fixture 之一。代表 fixture 的调用状态。
它有一个 param 字段,会被@pytest.fixture(params = tasks_to_try) 的params 列表中的一个元素填充。
也可以指定 ids。(只不过这里的 ids 也是函数,不是列表)
4|0四、内置 fixture
4|14.1 使用 tmpdir 和 tmpdir_factory
内置的 tmpdir 和 tmpdir_factory 负责在测试开始运行前创建临时文件目录,并在测试结束后删除。
tmpdir 的作用范围是函数级别,tmpdir_factory 的作用范围是会话级别。
使用 tmpdir_factory 替换这个脚本
pytest-num 会随着会话的递增而递增。pytest 会记录最近几次会话使用的根目录,更早的根目录记录则会被清理掉。(默认保留 3 次)
在其他作用范围内使用临时目录
tmpdir_factory 的作用范围是会话级别的,tmpdir 的作用范围是函数级别的。如果需要模块或类级别作用范围的目录,该怎么办?可以利用 tmpdir_factory 再创建一个 fixture
假设有一个测试模块,其中有很多测试用例要读取一个json文件。有下例:(放在 conftest.py下面)
上述代码创建了一个 json 文件。因为这个新 fixture 的作用范围是模块级别的,所以该 json 文件只需要被每个模块创建一次。
这里两个 测试用例 将使用同一个 json 文件。
4|24.2 使用 pytestconfig
内置 的 pytestconfig 可以通过命令行参数、选项、配置文件、插件、运行目录等方式来控制 pytest。
下面使用 pytest 的 hook 函数 pytest_addoption 添加几个命令行选项
以 pytest_addoption 添加的命令行选项必须通过插件来实现,或者在项目顶层目录的 conftest.py 文件中完成。它所在的 conftest.py 不能处于测试子目录下。
再运行 help
加下来就可以使用这些选项了
结果如下
因为 pytestconfig 是一个fixture,所以它也可以被其他 fixture 使用。
4|34.3 使用 cache
有时需要从一段测试会话传递信息给下一段会话很有用。
cache 的作用是存储一段测试会话的信息,在下一段测试会话中使用。使用 pytest 内置的 --last-failed 和 --failed-first 标识可以很好的展示 cache的功能。
如果要清空缓存,可以在测试会话开始前传入 --cache-clear
cache 的接口很简单
习惯上,键名以应用名字或插件名字开始,接着是 / ,然后是分隔开的键字符串。键值可以是任何可转化为 JSON 的东西,因为在 .cache 目录里是用 JSON 格式存储的。
以下是一个 fixture ,记录测试的耗时,并存储到 cache ,如果接下来的测试耗时大于之前的两倍,就抛出超时异常。
因为 fixture 设置为了 autouse,所以它不需要被测试用例引用。request 对象用来抓取键名中的 nodeid。nodeid是一个独特的标识,即便实在参数化测试中也能使用。
运行之后,看看 cache 里有什么:
接下来的每个测试都将读/写 cache。可以把原先的 fixture 拆分为两个小 fixture:一个作用范围是函数级别,用于测量运行时间;另一个作用范围是会话级别,用来读/写 cache。可如果这样做,就不能使用 cache fixture了,因为它的作用范围是函数级别的。
duration_cache 的作用范围是会话级别的。在所有测试用例运行之前,它会读取之前的 cache 记录(如果没有记录,就是一个空字典)。在上面的代码中,我们把读取后的字段和一个空字典都存储在名为 Duration 的 namedtuple中,并使用 current 和 last 来访问之。之后将这个 namedtuple 传递给 check_duration,check_duration的作用范围是函数级别的。当测试用例运行时,相同的 namedtuple 被传递给每个测试用例。当前测试的运行时间被存储在 d.current 字典里。测试结束后,汇总的 current 字段被保存在 cache 里。
4|44.4 使用 capsys
pytest 内置的 capsys 有两个功能:允许使用代码读取 stdout 和 strerr;可以临时禁止抓取日志输出。
假设某个函数要把欢迎信息输出到 stdout
这时候不能使用返回值来测试它,只能测试 stdout。可使用capsys来测试。
使用 strerr 的例子
pytest 通常会抓取测试用例及被测试代码的输出。仅当全部测试会话运行结束后,抓取到的输出才会随着失败的测试显示出来。-s 参数可以关闭这个功能,在测试仍在运行期间就把输出直接发送到 stdout。
有时候就是想用 print 打印,但是又不想被捕获。这时候可以是用 capsys.disabled() 临时让输出绕过默认的输出捕获机制。
运行如下:
正如你所看到的,不管有没有捕获输出,始终会显示 “always print this”。其他的打印正常,仅当 -s 标识的时候才会显示。(-s 表示关闭输出捕获)
也可以使用 capsys.readouterr() 捕获。这时候 就算 -s 也不能输出。
4|54.5 使用 monkeypatch
monkey patch 可以在运行期间对类或模块进行动态修改,在测试中,monkey patch 常用于替换被测试代码的部分运行环境,或者将输入依赖或输出依赖替换成更容易测试的对象或函数。
monkeypatch 提供以下函数:
raising 参数用于指示 pytest 是否在记录不存在时抛出异常。setenv() 函数里的 prepend 参数可以是一个字符,如果这样设置的话,name环境变量的值就是 value + prepend + <old value>
为了理解 monkeypatch 的实际应用方式,以下是用于生成配置文件的代码。
write_default_cheese_preferences() 函数既不含参数,又没有返回值,那么如何测试?它在当前用户目录中编写了一个文件,我们可以利用这点从测试测试。
一种方法是直接运行代码,检查文件的生成情况。在我们足够信任 read_cheese_preferences() 函数测试结果的前提下,可以直接把它运用到 write_default_cheese_preferences() 函数的测试里。
但是有一个问题,这样测试,预设值文件会被覆盖,这样不合适。
如果用户设置了 HOME 变量,那么 os.path.expanduser() 函数会把 ~ 替换为 HOME 环境变量的值。让我们创建一个临时目录并将 HOME 指向它。
看起来不错,但其中的 HOME 变量依赖于操作系统。查询 Python 官方文档,可以在 os.path.expanduser() 的介绍中找到这样一句话:“On Windows,HOME and USERPROFILE will be used if set,otherwise a combination of”。这个测试不适合 Windows。
用 expanduser 替换 HOME 环境变量
在测试中,cheese 模块中调用的 os.path.expanduser() 函数会被 lambda 表达式替换。原先该函数使用正则表达式模块的 re.sub() 函数,将 ~ 替换为我们新建的临时目录。现在已经使用了 setenv() 和 setattr() 函数来修改环境变量和属性。下面使用 setitem() 函数
有可能文件已经存在,所有要确保当 write_default_cheese_preferences() 被调用时,文件会被默认内容覆盖。
由于 _default_prefs 是字典,所有可以在测试运行时用 monkeypatch.setitem() 来修改字典中的条目。
我们使用过 setenv(),setattr() 和 setitem() 。有关 del 的几个函数在形式上与 set 非常相似,只不过它们是用来删除环境变量、属性和字典条目。最后的两个 monkeypatch 函数是有关路径操作的。
syspath_prepend(path) 在 sys.path 列表前加入一条路径,这可以提高你的新路径在模块搜索时的优先级。比如你可以采用这个方法,使用自定义的包、模块替换原先作用于系统范围的版本,接着使用 monkeypatch.syspatch_prepend() 函数来加入含有新版本模块的路径,这样,要测试的代码就会使用新版本的模块。
chdir(path) 可以在测试运行时改变当前的工作目录。这对于测试命令行脚本和其他依赖于当前目录的工具都很有用。你可以设置一个临时目录,然后使用 monkeypatch.chdir(the_tmpdir)。
4|64.6 使用 doctest_namespace
doctest 模块是 Python 标准库的一部分,借助它,可以在函数的文档字符串中放入示例代码,并通过测试确保有效。你可以使用 --doctest-modules 标识搜寻并运行 doctest 测试用例。
在构建被标注为 autouse 的fixture时,可以使用内置的 doctest_namespace,这能够使doctest 中的测试用例在运行时识别某些作用于 pytest 命名空间的字符标识,从而增强文档字符串的可读性。
下面的模块 unnecessary_math.py 有两个函数:multiply() 和 divide(),我们希望每个人都清楚地了解这两个函数。所以在文件和函数的文档字符传中都加入了一些使用例子:
unnecessary_math 名字太长了,我们决定使用 um 来代替它,所以在文档顶部使用了 import unnecessary_math as um。后面的文档字符串里的代码不包含import语句,但一直在使用 um。问题是 pytest 将每个字符串里的代码看成是不同的测试用例,顶部的 import 语句可以保证第一个例子通过,但是后面的会失败
一种解决办法是在每个文档字符串中加入 import 语句。
但是这样做分隔了文档字符串,。
第二种方法,是在 conftest.py 中使用内置的 doctest_namespace ,构建标记为 autouse 的 fixture,就可以解决之前的问题而且不用修改代码。
pytest 会把 um 添加到 doctest_namespace 中,并把它作为 unnecessary_math 模块的别名。这样设置 conftest.py 之后,在 conftest.py 的作用范围内的任意一个 doctest 测试用例都可以使用um
4|74.7 使用 recwarn
内置的 recwarn 可以用来检查待测代码产生的警告信息。在Python 里,可以添加警告信息,它们很像断言,但是并不阻止程序运行。
例如,我们想停止支持一个原本不该发布的函数,则可以在代码里设置警告信息。
可以用下面的测试用例来确保警告信息显示正确。
recwarn 的值就像是一个警告信息列表,列表里的每个警告信息都有 4 个属性 category、message、filename、lineno,从上面的代码中可以看到。
警告信息在测试开始后收集。如果你在意的警告信息出现在测试尾部,则可以在信息收集前使用 recwarn.clear() 清除不需要的内容。
除了 recwarn,pytest 还可以使用 pytest.warns() 来检查警告信息。
pytest.warns() 上下文管理器可以优雅地标识哪些代码需要检查警告信息。recwarn 提供了相似的功能。可以自己选择
5|0五、配置configuration
5|15.1 理解 pytest 的配置文件
pytest.ini:pytest 的主配置文件,可以改变 pytest 的默认行为,其中有很多可配置的选项。
conftest.py:是本地的插件库,其中的hook函数和fixture将作用域该文件所在的目录以及所有子目录
__init__.py:每个测试子目录都包含该文件时,那么在多个测试目录中可以出现同名测试文件。
tox.ini:它与pytest.ini 类似,只不过是 tox 的配置文件。你可以把 pytest 的配置都写在 tox.ini里,这样就不用同时使用 tox.ini 和 pytest.ini 两个文件。
5|25.2 用 pytest --help 查看 ini文件选项
5|35.3 更改默认命令行选项
如果测试的时候,经常要用到某些选项,又不想重复输入,这时可以使用 pytest.ini 文件里的 addopts 设置。下面是我自己常用的设置。
--rsxX 表示 pytest 报告所有测试用例被跳过、预计失败、预计失败但实际通过的原因。
-l 表示 pytest 报告所有失败测试的堆栈中的局部变量。
--tb=short 表示简化堆栈回溯信息,只保留文件和行数。
--strict 选项表示禁止使用未在配置文件中注册的标记。
5|45.4 注册标记来防范拼写错误
如果我们要标记,@pytest.mark.smoke ,但是拼错,@pytest.mark.somke , 默认情况下,这不会引起程序错误。pytest 会以为这是你创建的另一个标记。为了避免拼写错误,可以在 pytest.ini 文件里注册标记。
标记注册好后,可以通过 pytest --markers 来查看
没有注册的标记不会出现在 --markers 列表里。如果使用了 --strict 选项,遇到拼写错误的标记或未注册的标记就会报错。
这里 @pytest.mark.sooke 写错了。
如果你在 pytest.ini 文件里注册了标记,那么可以同时在 addopts 里加入 --strict
5|55.5 指定 pytest 的最低版本号
minversion 选项可以指定运行测试用例的 pytest 的最低版本。例如,测试两个浮点数的值是否非常接近。比如 approx()函数,但是这个功能 直到 pytest 3.0 才出现。
为了避免混淆,可以在使用 approx() 函数的项目中增加一行配置
5|65.6 指定 pytest 忽略某些目录
pytest 执行测试搜索时,会递归遍历所有子目录,包括某些本来不想遍历的目录。
可以使用 norecurse 选项简化 pytest 的搜索工作。norecurse 的默认设置是 .* build dist CVS_darcs {arch} 和 *.egg。因为有 .* ,所以将虚拟环境命名为 .venv 是一个好主意,所有以 . 开头的目录都不会被访问。但是,我习惯将它命名为 venv,那么需要把它加入 norecursedirs里。
5|75.7 指定测试目录
norecursedirs 告诉pytest 哪些路径不用访问,而 testpaths 则指示 pytest 去哪里访问。
testpaths 是一系列相对于根目录的路径,用于限定测试用例的搜索范围。只有在pytest未指定文件目录参数或测试用例标识符时,该选项才会启用
5|85.8 更改测试搜索的规则
pytest 根据一定的规则搜索并运行测试。标准的测试搜索规则如下:
- 从一个或多个目录开始查找。你可以在命令行指定文件名或目录名。如果未指定,则使用当前目录。
- 在该目录和所有子目录下递归查找测试模块。
- 测试模块是指文件名为 test_*.py 或 *_test.py 的文件。
- 在测试模块中查找以 test_开头的函数名。
- 查找名字以 Test开头的类。其中,首先筛选掉包含 __init_函数的类,再查找类中以 test_ 开头的类方法。
pytest_classes
通常,pytest 的测试搜索规则是寻找以 Test*开头的测试类,而且这个类不能有 __init__() 函数。要改类搜索命名格式的话可以如下。
python_files
可以更改默认的测试搜索规则,而不是仅查找以 test_* 开头的文件和以 *_test 结尾的文件。
python_functions
更改测试函数和方法的搜索方式
5|96.8 禁用XPASS
__EOF__

本文链接:https://www.cnblogs.com/dongye95/p/13488235.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!