10、pytest -- skip和xfail标记
实际工作中,测试用例的执行可能会依赖于一些外部条件,例如:只能运行在某个特定的操作系统(Windows
),或者我们本身期望它们测试失败,例如:被某个已知的Bug
所阻塞;如果我们能为这些用例提前打上标记,那么pytest
就相应地预处理它们,并提供一个更加准确的测试报告;
在这种场景下,常用的标记有:
skip
:只有当某些条件得到满足时,才执行测试用例,否则跳过整个测试用例的执行;例如,在非Windows
平台上跳过只支持Windows
系统的用例;xfail
:因为一个确切的原因,我们知道这个用例会失败;例如,对某个未实现的功能的测试,或者阻塞于某个已知Bug
的测试;
pytest
默认不显示skip
和xfail
用例的详细信息,我们可以通过-r
选项来自定义这种行为;
通常,我们使用一个字母作为一种类型的代表,具体的规则如下:
(f)ailed, (E)rror, (s)kipped, (x)failed, (X)passed, (p)assed, (P)assed with output, (a)ll except passed(p/P), or (A)ll
例如,显示结果为XFAIL
、XPASS
和SKIPPED
的用例:
pytest -rxXs
更多细节可以参考:2、使用和调用 -- 总结报告
1. 跳过测试用例的执行
1.1. @pytest.mark.skip
装饰器
跳过执行某个用例最简单的方式就是使用@pytest.mark.skip
装饰器,并且可以设置一个可选参数reason
,表明跳过的原因;
@pytest.mark.skip(reason="no way of currently testing this")
def test_the_unknown():
...
1.2. pytest.skip
方法
如果我们想在测试执行期间(也可以在SetUp/TearDown
期间)强制跳过后续的步骤,可以考虑pytest.skip()
方法,它同样可以设置一个参数msg
,表明跳过的原因;
def test_function():
if not valid_config():
pytest.skip("unsupported configuration")
另外,我们还可以为其设置一个布尔型的参数allow_module_level
(默认是False
),表明是否允许在模块中调用这个方法,如果置为True
,则跳过模块中剩余的部分;
例如,在Windows
平台下,不测试这个模块:
import sys
import pytest
if not sys.platform.startswith("win"):
pytest.skip("skipping windows-only tests", allow_module_level=True)
注意:
当在用例中设置
allow_module_level
参数时,并不会生效;def test_one():
pytest.skip("跳出", allow_module_level=True) def test_two():
assert 1
也就是说,在上述示例中,并不会跳过
test_two
用例;
1.3. @pytest.mark.skipif
装饰器
如果我们想有条件的跳过某些测试用例的执行,可以使用@pytest.mark.skipif
装饰器;
例如,当python
的版本小于3.6
时,跳过用例:
import sys
@pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python3.6 or higher")
def test_function():
...
我们也可以在两个模块之间共享pytest.mark.skipif
标记;
例如,我们在test_module.py
中定义了minversion
,表明当python
的最低支持版本:
# src/chapter-10/test_module.py
import sys
import pytest
minversion = pytest.mark.skipif(sys.version_info < (3, 8),
reason='请使用 python 3.8 或者更高的版本。')
@minversion
def test_one():
assert True
并且,在test_other_module.py
中引入了minversion
:
# src/chapter-10/test_other_module.py
from test_module import minversion
@minversion
def test_two():
assert True
现在,我们来执行这两个用例(当前虚拟环境的python
版本为3.7.3
):
λ pipenv run pytest -rs -k 'module' src/chapter-10/
================================ test session starts =================================
platform win32 -- Python 3.7.3, pytest-5.1.3, py-1.8.0, pluggy-0.13.0
rootdir: D:\Personal Files\Projects\pytest-chinese-doc
collected 2 items
src\chapter-10\test_module.py s [ 50%]
src\chapter-10\test_other_module.py s [100%]
============================== short test summary info ===============================
SKIPPED [1] src\chapter-10\test_module.py:29: 请使用 python 3.8 或者更高的版本。
SKIPPED [1] src\chapter-10\test_other_module.py:26: 请使用 python 3.8 或者更高的版本。
================================= 2 skipped in 0.03s =================================
可以看到,minversion
在两个测试模块中都生效了;
因此,在大型的测试项目中,可以在一个文件中定义所有的执行条件,需要时再引入到模块中;
另外,需要注意的是,当一个用例指定了多个skipif
条件时,只需满足其中一个,就可以跳过这个用例的执行;
注意:不存在
pytest.skipif()
的方法;
1.4. pytest.importorskip
方法
当引入某个模块失败时,我们同样可以跳过后续部分的执行;
docutils = pytest.importorskip("docutils")
我们也可以为其指定一个最低满足要求的版本,判断的依据是检查引入模块的__version__
属性:
docutils = pytest.importorskip("docutils", minversion="0.3")
我们还可以再为其指定一个reason
参数,表明跳过的原因;
我们注意到
pytest.importorskip
和pytest.skip(allow_module_level=True)
都可以在模块的引入阶段跳过剩余部分;实际上,在源码中它们抛出的都是同样的异常:# pytest.skip(allow_module_level=True) raise Skipped(msg=msg, allow_module_level=allow_module_level)
# pytest.importorskip() raise Skipped(reason, allow_module_level=True) from None
只是
importorskip
额外增加了minversion
参数:# _pytest/outcomes.py if minversion is None:
return mod
verattr = getattr(mod, "__version__", None)
if minversion is not None:
if verattr is None or Version(verattr) < Version(minversion):
raise Skipped(
"module %r has __version__ %r, required is: %r"
% (modname, verattr, minversion),
allow_module_level=True,
)
从中我们也证实了,它实际检查的是模块的
__version__
属性;所以,对于一般场景下,使用下面的方法可以实现同样的效果:
try:
import docutils
except ImportError:
pytest.skip("could not import 'docutils': No module named 'docutils'",
allow_module_level=True)
1.5. 跳过测试类
在类上应用@pytest.mark.skip
或@pytest.mark.skipif
:
# src/chapter-10/test_skip_class.py
import pytest
@pytest.mark.skip("作用于类中的每一个用例,所以 pytest 共收集到两个 SKIPPED 的用例。")
class TestMyClass():
def test_one(self):
assert True
def test_two(self):
assert True
1.6. 跳过测试模块
在模块中定义pytestmark
变量(推荐):
# src/chapter-10/test_skip_module.py
import pytest
pytestmark = pytest.mark.skip('作用于模块中的每一个用例,所以 pytest 共收集到两个 SKIPPED 的用例。')
def test_one():
assert True
def test_two():
assert True
或者,在模块中调用pytest.skip
方法,并设置allow_module_level=True
:
# src/chapter-10/test_skip_module.py
import pytest
pytest.skip('在用例收集阶段就已经跳出了,所以不会收集到任何用例。', allow_module_level=True)
def test_one():
assert True
def test_two():
assert True
1.7. 跳过指定文件或目录
通过在conftest.py
中配置collect_ignore_glob
项,可以在用例的收集阶段跳过指定的文件和目录;
例如,跳过当前测试目录中文件名匹配test_*.py
规则的文件和config
的子文件夹sub
中的文件:
collect_ignore_glob = ['test*.py', 'config/sub']
更多细节可以参考:https://docs.pytest.org/en/5.1.3/example/pythoncollection.html#customizing-test-collection
1.8. 总结
pytest.mark.skip |
pytest.mark.skipif |
pytest.skip |
pytest.importorskip |
conftest.py |
|
---|---|---|---|---|---|
用例 | @pytest.mark.skip() |
@pytest.mark.skipif() |
pytest.skip(msg='') |
/ | / |
类 | @pytest.mark.skip() |
@pytest.mark.skipif() |
/ | / | / |
模块 | pytestmark = pytest.mark.skip() |
pytestmark = pytest.mark.skipif() |
pytest.skip(allow_module_level=True) |
pytestmark = pytest.importorskip() |
/ |
文件或目录 | / | / | / | / | collect_ignore_glob |
2. 标记用例为预期失败的
我们可以使用@pytest.mark.xfail
标记用例,表示期望这个用例执行失败;
用例会正常执行,只是失败时不再显示堆栈信息,最终的结果有两个:用例执行失败时(XFAIL
:符合预期的失败)、用例执行成功时(XPASS
:不符合预期的成功)
另外,我们也可以通过pytest.xfail
方法在用例执行过程中直接标记用例结果为XFAIL
,并跳过剩余的部分:
def test_function():
if not valid_config():
pytest.xfail("failing configuration (but should work)")
同样可以为pytest.xfail
指定一个reason
参数,表明原因;
下面我们来重点看一下@pytest.mark.xfail
的用法:
condition
位置参数,默认值为None
和
@pytest.mark.skipif
一样,它也可以接收一个python
表达式,表明只有满足条件时才标记用例;例如,只在
pytest 3.6
版本以上标记用例:@pytest.mark.xfail(sys.version_info >= (3, 6), reason="python3.6 api changes")
def test_function():
...
reason
关键字参数,默认值为None
可以指定一个字符串,表明标记用例的原因;
strict
关键字参数,默认值为False
当
strict=False
时,如果用例执行失败,结果标记为XFAIL
,表示符合预期的失败;如果用例执行成功,结果标记为XPASS
,表示不符合预期的成功;当
strict=True
时,如果用例执行成功,结果将标记为FAILED
,而不再是XPASS
了;我们也可以在
pytest.ini
文件中配置:[pytest]
xfail_strict=true
raises
关键字参数,默认值为None
可以指定为一个异常类或者多个异常类的元组,表明我们期望用例上报指定的异常;
如果用例的失败不是因为所期望的异常导致的,
pytest
将会把测试结果标记为FAILED
;run
关键字参数,默认值为True
:当
run=False
时,pytest
不会再执行测试用例,直接将结果标记为XFAIL
;
我们以下表来总结不同参数组合对测试结果的影响(其中xfail = pytest.mark.xfail
):
@xfail() |
@xfail(strict=True) |
@xfail(raises=IndexError) |
@xfail(strict=True, raises=IndexError) |
@xfail(..., run=False) |
|
---|---|---|---|---|---|
用例测试成功 | XPASS |
FAILED |
XPASS |
FAILED |
XFAIL |
用例测试失败,上报AssertionError |
XFAIL |
XFAIL |
FAILED |
FAILED |
XFAIL |
用例上报IndexError |
XFAIL |
XFAIL |
XFAIL |
XFAIL |
XFAIL |
2.1. 去使能xfail
标记
我们可以通过命令行选项pytest --runxfail
来去使能xfail
标记,使这些用例变成正常执行的用例,仿佛没有被标记过一样:
同样,pytest.xfail()
方法也将会失效;
3. 结合pytest.param
方法
pytest.param
方法可用于为@pytest.mark.parametrize
或者参数化的fixture
指定一个具体的实参,它有一个关键字参数marks
,可以接收一个或一组标记,用于标记这轮测试的用例;
我们以下面的例子来说明:
# src/chapter-10/test_params.py
import pytest
import sys
@pytest.mark.parametrize(
('n', 'expected'),
[(2, 1),
pytest.param(2, 1, marks=pytest.mark.xfail(), id='XPASS'),
pytest.param(0, 1, marks=pytest.mark.xfail(raises=ZeroDivisionError), id='XFAIL'),
pytest.param(1, 2, marks=pytest.mark.skip(reason='无效的参数,跳过执行')),
pytest.param(1, 2, marks=pytest.mark.skipif(sys.version_info <= (3, 8), reason='请使用3.8及以上版本的python。'))])
def test_params(n, expected):
assert 2 / n == expected
执行:
λ pipenv run pytest -rA src/chapter-10/test_params.py
================================ test session starts =================================
platform win32 -- Python 3.7.3, pytest-5.1.3, py-1.8.0, pluggy-0.13.0
rootdir: D:\Personal Files\Projects\pytest-chinese-doc
collected 5 items
src\chapter-10\test_params.py .Xxss [100%]
======================================= PASSES =======================================
============================== short test summary info ===============================
PASSED src/chapter-10/test_params.py::test_params[2-1]
SKIPPED [1] src\chapter-10\test_params.py:26: 无效的参数,跳过执行
SKIPPED [1] src\chapter-10\test_params.py:26: 请使用3.8及以上版本的python。
XFAIL src/chapter-10/test_params.py::test_params[XFAIL]
XPASS src/chapter-10/test_params.py::test_params[XPASS]
================= 1 passed, 2 skipped, 1 xfailed, 1 xpassed in 0.08s =================
关于参数化的fixture
的细节可以参考:4、fixtures:明确的、模块化的和可扩展的 -- 在参数化的fixture中标记用例
10、pytest -- skip和xfail标记的更多相关文章
- 【pytest系列】- mark标记功能详细介绍
如果想从头学起pytest,可以去看看这个系列的文章! https://www.cnblogs.com/miki-peng/category/1960108.html mark标记 在实际工作中, ...
- pytest skip的使用
skip跳过用例(无条件跳过,不运行用例) 使用方法: 1.使用跳过装饰器 class TestClass(): @pytest.mark.skip(reason='no way of current ...
- pytest mark中的skip,skipif, xfail
这些测试的过滤,或是对返回值的二重判断, 可以让测试过程更精准,测试结果更可控, 并可以更高层的应用测试脚本来保持批量化执行. import pytest import tasks from task ...
- pytest 14 使用自定义标记mark
标记失败用到的情况是,本身就知道这是失败的例子,所以,不用让他运行,直接跳过.或者是依赖于某个方法,某个方式失败的话,用例直接标记成失败. 标记失败有两种方法,一种是方法内部,一种是方法外部.内部用p ...
- pytest 13 使用自定义标记mark
前言: pytest可以规定那些要跑,那些不跑,跑特定的哪些?比如以下的这个例子: #!/usr/bin/env/python # -*-coding:utf-8-*- import pytest @ ...
- 11、pytest -- 测试的参数化
目录 1. @pytest.mark.parametrize标记 1.1. empty_parameter_set_mark选项 1.2. 多个标记组合 1.3. 标记测试模块 2. pytest_g ...
- pytest -- 测试的参数化
目录 1. @pytest.mark.parametrize标记 1.1. empty_parameter_set_mark选项 1.2. 多个标记组合 1.3. 标记测试模块 2. pytest_g ...
- pytest文档16-用例a失败,跳过测试用例b和c并标记失败xfail
前言 当用例a失败的时候,如果用例b和用例c都是依赖于第一个用例的结果,那可以直接跳过用例b和c的测试,直接给他标记失败xfail 用到的场景,登录是第一个用例,登录之后的操作b是第二个用例,登录之后 ...
- pytest十:用例 a 失败,跳过测试用例 b 和 c 并标记失败 xfail
当用例 a 失败的时候,如果用例 b 和用例 c 都是依赖于第一个用例的结果,那可以直接跳过用例 b 和 c 的测试,直接给他标记失败 xfail用到的场景,登录是第一个用例,登录之后的操作 b 是第 ...
随机推荐
- RBD 基本使用 - Storage6
块存储管理系列文章 (1)RBD 基本使用 - Storage6 (2)iSCSI 网关管理 (3)使用 librbd 将虚拟机运行在 Ceph RBD (4)RBD Mirror 容灾 Ceph 块 ...
- Web调用Linux客户端remmina运维
相信你遇到过这样的场景,在浏览器网页中点击QQ图标咨询,就能唤起本机的装的qq或tim,下载百度网盘的资源的时候,点击链接浏览器会启动本地百度云进行下载. 最近因为项目需要,也要实现类似的操作,不 ...
- python编程基础之十六
for in 循环,与其说是循环不如说精确点交遍历 for 变量名 in + 迭代对象 语句A else: 语句B 作用:一次访问迭代对象中的元素并赋值给变量 循环终止时,执行else语句块,如果br ...
- 配置code::blocks的glut环境
code::blocks很小,特别适合小型项目及家用旧电脑上MingW下编程,当然windows还是安装的Visual Studio办公用的,现把配置过程记录一遍. 1.在百度搜code::block ...
- http服务端架构演进
摘要 在详解http报文相关文章中我们介绍了http协议是如何工作的,那么构建一个真实的网站还需要引入组件呢?一些常见的名词到底是什么含义呢? 什么叫正向代理,什么叫反向代理 服务代理与负载均衡的差别 ...
- Blazor(一):运行初体验,全新的.net web的开发
官网:https://dotnet.microsoft.com/apps/aspnet/web-apps/client 作者BBS:http://bbs.hslcommunication.cn/ 我们 ...
- 新手入门HTML5开发,你必须先搞懂这6个问题
凭借着跨平台,实时更新,无需安装,易于分发等众多优点,HTML5受到越来越多企业的青睐.而凭借着入门相对简单的优势,很多人编程初学者都选择学习HTML5.但对于初学者来说,学习HTML5之前,会有很多 ...
- Ajax:后台jquery实现ajax无刷新删除数据及demo
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8gAAAFSCAIAAAChUmFZAAAgAElEQVR4nO29z4scWZbn2/+Hb30zi8
- DM7经常使用的命令汇总
由于DM7兼容oracle ,所以当你不知道某个命令时,大抵就是可以参照oracle的命令及语法,当然有极少的情况会不一样.常用命令如下: 1.连接登录 disql SYSDBA/SYSDBA@223 ...
- 虚拟机Ubuntu系统无法连接网络解决方案
宿主机连接wifi,虚拟机无法联网 查看是否有网络图标 操作一: sudo service network-manager stopsudo rm /var/lib/NetworkManager/Ne ...