文章摘要
本文作为上篇 Pytest 零基础速通指南的续篇,在掌握用例编写、命令行执行、基础运行结果解读的前提下,递进讲解 Pytest 五大核心高阶实战能力:测试用例 Mark 标记分类管理、数据驱动参数化、Fixture 夹具前置后置依赖封装、Allure 等第三方插件与企业级可视化测试报告落地,最终结合 Selenium 完成 Web 自动化完整项目实战。全文配套可直接运行的代码案例,解决自动化测试中用例分组执行、多组数据迭代、测试环境复用、缺陷报告输出等企业真实痛点,帮你完整搭建可落地的 Python 自动化测试项目体系。以下是剩余五大章节的介绍。从第六部分开始讲。
六、Pytest测试框架------标记Mark
标记可以让测试用例与众不同,进而可以让测试用例区别对待。这里可以分为两种标记类型:
1.用户自定义标记
用户自定义的标记,只能实现用例筛选(也就是上篇文章提到的-m)。
这里实现步骤主要是:先注册、再标记,后筛选。
(1)注册这个步骤可以通过两种方式来实现,一种是参数,另一种就是配置文件。这里来演示一下在pytest.ini配置文件的注册。
先在配置文件中输入这段内容:
python
[pytest]
markers =
api:接口测试
web:UI测试
ut:单元测试
login:登录相关
pay:支付相关
然后在终端执行:pytest --markers 然后就能看到:

(2)添加标记,直接在pycharm当中添加标记,代码如下所示:
python
import pytest
def add(a, b):
return a + b
def test_print():
assert 1==2
class TestAdd:
@pytest.mark.api
# 数字
def test_int(self):
res = add(1, 2)
assert res == 3
@pytest.mark.ui
# 返回字符串(字符串拼接)
def test_str(self):
res = add("1", "2")
assert res == "12"
# 列表拼接
@pytest.mark.pay
def test_list(self):
res = add([1], [2,3,4])
assert res == [1, 2, 3, 4]
这里,添加了三个标记,分别是:@pytest.mark.api,@pytest.mark.web,@@pytest.mark.pay。与上面注册的内容相对应。然后运行,结果如下图:

看到这张图片,就表明此时已经标记成功。
**注:**如果你想要执行以上用例的某一个用例,这里就用到了上一篇内容提到的-m参数。
直接输入pytest -M 想要执行用例的mark就能得到结果,这里以api-mark用例为例。

图中箭头所指的部分就是表示其余的6个测试用例未被选中。
2.框架内置标记(重点学习!!!)
这里先了解一下和用户自定义标记的区别:
- 无需注册(已经有了),可以直接使用
- 不仅可以筛选,而且还能增加特殊效果
- 不同的标记,还能增加不同的特殊效果
对于第三点,这里可以简单的学习一下。
(1)skip:无条件跳过
(2)skipif:有条件跳过
(3)xfail:预期失败
(4)parametrize:参数化
(5)usefixture:使用fixture(这里在后面会讲到如何使用)
接下来,在上面演示的用例项目中来演示前四种内置标记。

在上面的测试用例中,分别加入这几种标记,然后复制粘贴最后一个测试用例的断言,改为!=。

**注:**这张图片上的代码有一个小错误,复制粘贴的test_开头的名字不能一样,删掉其中一个的list后面的_就不报错了。

这里需要注意,skipif使用时需要写跳过原因,不然就会报错。上面图片画红框部分是我写的内容,以供参考。
接着运行,可以看到以下运行结果:

看到这张图片,就是符合预期的记录。
接下来,讲一下参数化(parametrize)。
在讲解之前,你肯定听说过数据驱动性测试。这里数据驱动测试=参数化测试+数据文件 。这里产生的效果就是根据数据文件的内容来动态的决定用例的数量、内容。
在pytest框架中我们使用的是参数化测试,但是在项目当中实际上使用的是数据驱动测试 。接下来分一个章节来重点讲一下数据驱动测试的参数。
七、Pytest------数据驱动测试参数
首先,在之前的项目当中创建一个数据文件,命名为data.csv。
然后在这个文件当中创建几组数据,如图所示。

这里第一行表示表头 ,下面数据的前两列表示函数的参数,最后一列作为函数的返回值。
接着定义一个新的测试用例,在配置文件pytest.ini当中注册一个新的标记:**ddt------数据驱动测试。**然后使用参数化内置标记来表明希望为用例提供什么样的参数。具体代码如下所示:
python
@pytest.mark.parametrize(
"a,b,c"
)
具体测试用例如下:

这里表示:**从数据文件中加载出来的三个参数在函数当中进行接收,然后传递给用例进行使用。**接下来的问题就脱离了pytest框架的支持,需要我们自己去执行,把结果加载出来。
接下来,展示一下如何去加载结果。
(1)创建一个ceshi.py的文件,随意命名即可。
(2)导入csv模块,专门用来读取内容;打开该文件,进行打印输出该数据内容,在终端看效果。
python
import csv
from _pyrepl import reader
f=open("data.csv")
reader= csv.DictReader(f)
print(list(reader))
这是ceshi.py文件当中的内容,点击运行之后,能在终端上看到打印出来的数据,如图所示。

注意:这里是用字典的方式来读取的数据,如果只想要数字,那么只需要选择普通的方式去读取内容即可。


这里第一行是表头,不需要打印,那么只需要更改打印的内容为切片。


如果以上的内容都能理解,那么就可以不用去写那么多内容,封装一个函数就能实现。
python
import csv
def read_csv(path):
f = open(path)
reader = csv.reader(f)
return list(reader)[1:]
这段代码就封装好了一个函数。然后就可以在刚才的test_add.py当中导入csv了。具体修改部分如下:


接着,输入pytest -m ddt来看一下运行效果。

这里有一个小问题,就是没有对这个数据做转换,转换成字符串 ,这里读取的是数字。
如果将这个测试用例的数据转换为int的格式,会得到不一样的结果,如图所示:

这里就会看到三个通过,一个失败,失败的原因是4+4≠7。
通过这个例子,你就可以理解数据文件,驱动用例执行的数量、内容这句话了。
八、夹具------fixture的使用(更难,更重要)
首先先解释一下什么是夹具,简单来说,夹具就是在用例执行之前、执行之后,能够自动运行代码。
这里介绍三个场景:
(1)之前:加密参数/之后:解密结果
(2)之前:启动浏览器/之后:关闭浏览器
(3)之前:注册、登录账号/之后:删除账号
总结一下就是------夹具就是测试用例执行前后自动执行的初始化和销毁操作,常用于浏览器启停、参数加解密、测试账号创建与销毁,保证测试环境独立干净。
记住这些之后,先学习如何创建一个fixture。
- 第一步,先创建一个全新的用例,命名为test_xiaoyu.py。

- 第二步,在测试用例当中输入以下内容。

- 第三步,就要创建fixture了;先创建一个函数(当然,这里不是普通的函数,需要加装饰器来修饰,用来实现用例的前置和后置)。

- 第四部,就是添加一个yield关键字。(yield关键字用大白话来说就是yield 卡在中间,前面做前置,用例跑完回头执行 yield 后面的清理代码,这就是夹具靠它实现前置后置的核心原因。)
python
@pytest.fixture
def f():
# 前置操作
yield
# 后置操作
这里是一个最基本的fixture,但是这里看不到效果,接下来添加一些代码来测试一下效果,学习一下如何使用fixture。
- 使用fixture最基本的方式就是------在用例的参数列表中直接加入fixture名字即可。
python
# 这个没有以test_开头,说明不是测试用例,这里加一个装饰器就表明是fixture了
@pytest.fixture
def f():
print(datetime.now(),'用例开始执行')
# 前置操作
yield
# 后置操作
print(datetime.now(),'用例执行完毕')
# 用例1
def test_1(f):
pass #开始执行用例

- 第二种使用方式是------给用例加上userfixtures标记。
python
#用例2
@pytest.mark.usefixtures("f")
def test_2():
pass

这里可以看到,输入pytest -vs命令之后,用例二在使用标记的情况下也能够得到同样的效果。
接下来呢,我们再学习一下fixture的高级用法。
1.自动使用。(这里可以加入autouse=True这个自动生效的夹具,不需要在测试函数形参里手动传入,当前作用域下所有用例都会自动执行它的前置 + 后置代码。)

这里就可以看到这个自动生效的夹具效果。
2.依赖使用。(这里表示 :fixture不仅可以被测试用例使用,也可以被另一个可以直接用的fixture拿来使用。)
这里来讲一下写简历上的一个小技巧:
你可能会写到这些内容------linux:使用linux来进行编译;git:使用git来进行版本控制
如果你要写pytest测试框架的fixture,那你可以写
使用fixture来进行前后置自动操作。
这里可以输入另一个fixture(ff),然后打印输出一句话"我是fixture,但是也被fixture自己使用"。
python
@pytest.fixture()
def ff():
print("我是fixture,但是也被fixture自己使用")
然后在其他fixture上调用这个fixture,执行看一下效果,如下图所示。

3.返回内容。(这里内容可以先简单学习,后面还会讲接口自动化封装------接口管理)
你需要知道------这里虽然从python语法来看,函数中可以有多个yield,但是在pytest框架中只能有一个yield 。当你使用yield传递一个数据(接口关联、加密数据、函数调用结果等任意东西)时,在传递后在终端能看到传递的结果。

4.范围共享。(可以指定范围共享来减少每一个用例使用fixture的时间。)
一般情况下,会进行默认范围的共享。
- 默认范围:function
- 全局范围:session

当你输入全局范围的session时会发现会执行完全部的用例后才出现用例执行完毕,这里就实现了全局范围的范围共享。【注:这里只实现了单个文件的用例范围共享,而不是所有python文件的共享,如果你再创建一个新的.py文件,实际上是会报错的,报错原因往往是f或者ff找不到。】
- 这里可以使用confests.py来实现所有不同文件用例的范围共享。(session和conftest.py这两个都要满足)
(1)首先,在这个项目外层(建议根目录)新建一个conftest.py文件。
(2)然后,将共享的fixture复制粘贴到这个文件当中。

(3)最后,输入命令观看运行效果。如下图所示:

这里,你就会发现所有的测试用例执行完毕之后才会打印一个时间,这是真正意义上的全局共享。
九、插件管理(常用第三方插件与企业级测试报告)
你需要知道,pytest插件生态是pytest特别的优势之处。
这里,你需要先了解插件的分类:
- 不需要安装:内置插件(不能卸载,是强制使用的)
- 需要安装:第三方插件
接着,再了解一下常用的pytest插件以及安装插件的一些命令:
-
pytest-cov--- 代码覆盖率
-
pytest-xdist--- 并行测试
-
pytest-mock--- mock 支持
-
pytest-timeout --- 超时控制
-
pytest-asyncio--- 异步测试
单个安装
pip install pytest-cov(插件名------选择几个想要安装的即可)
批量安装(建议使用这个命令来安装准备插件)
pip install pytest-cov pytest-xdist pytest-mock
指定版本
pip install pytest-cov==4.1.0

在终端上输入第二个批量安装的命令之后,出现这个结果,表示插件已经安装成功。
但是,第三方插件是不需要强制使用的,为了深入了解这些插件是如何调用的,这里先学习一下插件管理。
- 使用**-p abc** (abc表示插件的名称 )命令来启用插件,查看是否有该插件。(在查看时需要先用以上的一些命令来安装准备一些插件。)
- 接着,验证插件的安装使用情况。当你输入pytest --html=report.html这段命令时,会在项目当中生成一个report.html的文件报告,如下图所示。

这里,还有终端的输出展示。

-
这里,再结合-p abc这个命令就能使用该插件。完整命令是
pytest --html=report.html -p html

这是report.html里面的内容,当你运行上面的命令之后,就能正常运行该插件,但是如果在-p 后面的html前面加上no:该插件就被阻止运行了。【总结:启用:-p 插件名 禁用:-p no:插件名】
简单总结一下插件的几种使用方式。
- 参数
- 配置文件
- fixture
- mark
常用第三方插件
当你打开pytest官网(中文版):pytest 文档 - pytest 测试框架就能看到收录的所有插件,有1487个,可以自行学习。
这里来列举几个典型的常用三方插件。
(1)pytest.html
用途------生成html测试报告
安装命令:pip install pytest-html
使用(参数):pytest --html=report.html --self-contained-html
配置文件:在pytest.ini中加入addopts= --html=report.html --self-contained-html, 然后在终端执行pytest也能使用到该插件。


你还能点击该蓝色部分的链接,在浏览器打开该文件,看到测试用例的所有信息,如下图所示:

(2)pytest-xdist
用途:用来分布式执行,也就是一个任务去分给不同的人来完成。
安装:和上面插件一样,只需要更改插件名即可。
使用:-n N(N表示需要调度的进程数,可以是3也可以是100等数字)

输入命令之后,会发现该测试用例的执行时间达到了8.52s,执行时间变慢了,因为这是分布式执行的。这就说明在使用分布式的时候,一定会有资源调度的开销。
注: 这就说明,在使用这个插件时,只有在任务本身耗时较长、超出调度成本很多 的时候,才是有意义的。如果用例当中存在强烈的依赖关系,那就不能使用该插件。(分布式执行,有并发问题------资源竞争、乱序)
(3)pytest-rerunfailures(网络波动、UI渲染)
用途:用例失败之后,重新执行
安装:同理
使用:--reruns 5 --reruns-delay 1
这里新建一个用例,命名为test_rerun.py来测试一下效果。
用例中输入一个测试0到9的随机数,并断言这个数是否>=5。输入以下代码:
python
import random
import pytest
@pytest.mark.ut
def test_rerun():
x = random.randint(0,9)
assert x>=5
然后使用pytest -m ut,筛选用例,只执行ut用例,效果如下图所示:

第一次执行该命令,是失败的。

第二次执行该命令,也是失败的。

第三次是成功的。
这里不难看出,这个测试用例的结果是随机的,具有不稳定性。(这是情况下是好的)
而加入reruns这个参数命令,就能模拟终端用户在遇到问题时刷新进行修复。reruns后面加入的次数就是刷新的次数,即模拟用户重试五次。


这种用户通过刷新使用例勉强通过的,是可以接受的。(重试次数一两次还好,但是太多,比如25次就太离谱,不能算作通过。)
(4)pytest-result-log(无脑使用)
用途:把用例的执行结果记录到日志文件中。
安装:同上。
使用(配置文件):
python
log_file=./logs/pytest.log
log_file_level=info
log_file_format=%(levelname)-8s %(asctime)s[%(name)s:%(lineno)s] :%(message)s
log_file_date_format =%Y-%m-%d %H:%M:%S
;记录用例执行结果
result_log_enable=1
;记录用例分割线
result_log_separator=1
;分割线等级
result_log_level_separator=warning
;异常信息等级
result_log_level_verbose=info
在配置文件当中加入这段代码。

然后再执行pytest -m ut,查看一下项目当中的logs文件夹,然后就能看到日志文件的内容------里面包含用例的开始时间、结束时间,中间是用例的执行结果。

这里附上英文版的pytest插件学习链接:Pytest Plugin List - pytest documentation
综合应用------企业级测试报告(Allure)
首先,你需要知道的是,市面上目前主流的是使用Allure来生成测试报告,因此,学习allure是很必要的。附上系统性的学习指南:Allure使用教程 - 官方文档汉化 - 搬砖路上的大马猴 - 博客园
Allure是一个测试报告框架,你需要在pytest中安装。
bash
pip install allure-pytest
这是安装命令,与前面不太一样。

出现这个页面,表明allure安装成功。
接下来需要进行配置。同样是在pytest.ini文件当中。

这段配置文件中的两个参数分别表示,一个是指定临时的数据目录,另一个是清除原有的临时数据。
接着执行用例,查看测试结果。

这里,你会发现这里只生成了数据,而没有生成测试报告。这里我们还需要生成报告的一个步骤。
需要执行以下这个命令:
python
allure generate -o report -c temps
注:如果运行出现了下面图片中的报错,不要担心,可以询问AI来解决问题。
这是我查到的原因:allure 不是 Python 包,是独立的命令行工具,PowerShell 识别不到,也就是:本机的Allure 命令行工具没安装 / 安装后没配置系统环境变量 PATH。
安装一下就可以了。可以参考这篇文章:allure的安装配置、使用 - 雪儿来 - 博客园
安装配置完allure之后,再次运行该命令,就会得到以下内容:

这个时候,再去查看项目的文件夹,就会发现有一个report的文件夹,这里,这个报告就出现了。

这里,你可以点击index.html,在浏览器打开,就可以看到可视化的测试用例展示。如下图:

小贴士:你有没有注意到这个前端展示是英文的呀,如果你是小白,想要使用中文来学习,那么你可以使用这个命令在终端输入,就能转换为中文。
pythonallure generate temps -c -o report --report-language zh如果还想用英文还能转换回来,使用这个命令:
allure generate temps -c -o report --report-language en
pythonallure generate temps -c -o report --report-language en
除了可以使用终端命令来启动allure之外,还能使用代码来直接启动。
先在pytest.ini配置文件当中导入只执行一个ut测试用例的部分:

然后在main.py当中输入这段导入模块:

接着右键运行该项目中的main,查看是否和输入终端命令行一样,能够得到日志内容与测试报告。(如果测试失败,要尝试自己寻找原因,进行多次测试。)

这个就是使用代码生成的测试报告,与终端命令行效果一致。
这里,你还需要知道allure支持对用例进行分组和关联(敏捷开发术语)。这里来介绍allure里面的装饰器。
首先,创建一个test_allure.py的文件,然后添加有关装饰器的代码。
这里有四种常见的allure装饰器,简单介绍一下,分别是:
@allure.epic (史诗 项目) @allure.feature (主题 模块) @allure.story (故事 功能) @allure.title (标题 用例)
不管是什么装饰器,只要使用了同一组装饰器,就自动并入一组。
这里来创建两个测试用例,来展示一下效果。
python
import allure
import pytest
@allure.epic('lxc自动化测试')
@allure.feature('pytest训练营')
@allure.story('mark标记和筛选')
@allure.title('实现筛选用例')
@pytest.mark.ut
def test_a():
pass
@allure.epic('lxc自动化测试')
@allure.feature('pytest训练营')
@allure.story('fixture前置和后置')
@allure.title('使用fixture用例')
@pytest.mark.ut
def test_b():
pass
这是测试用例,上面规定了不同的内容,运行之后,会得到:

通过这张图片,你就能看到一个不属于任何分组的test_rerun,还能看到属于"lxc自动化测试"同一分组的测试用例。在做企业级项目汇报的时候,这张图片上的分组就能直观地展示出你的工作量和价值,领导可以清晰易懂的看出哪些测试用例是失败的,哪些是成功的。
接下来,学会融会贯通,做一个Web自动化测试的实战。
十、Web自动化测试实战(需要selenium)
准备工作与环境搭建
首先,你需要知道pytest仅仅进行用例管理,不会控制浏览器,需要借助新的工具,也就是selenium 。这里附上一个链接详细学习selenium:Selenium 简介 | 菜鸟教程
注意:1.只了解selenium
- 搜索关于selenium的pytest插件 (可以在pytest插件官网直接搜索带selenium的就行)

第一步,先安装有关selenium的插件,记得还要在本机上下载有关selenium的环境。

参考上面的链接,按步骤操作即可。

下载好之后,使用验证命令来验证是否安装成功。如果安装完毕,就进入下一步,开始实战。

安装成功,进入实战。
实战
第一步,在tests中新建一个test_web.py的文件,然后添加以下内容:

接着,继续添加有关selenium的代码:
先在配置文件中加入这段代码:

然后,更改部分代码为下面部分:

完整代码是:
python
import pytest
import time
# 注册标记,和pytest.ini对应
@pytest.mark.web
def test_open_baidu(selenium):
# 访问百度,建议用https
selenium.get("https://www.baidu.com")
# 打印当前标题,方便控制台看执行结果
print("页面标题:", selenium.title)
time.sleep(3)
# 断言,校验是否打开成功
assert "百度" in selenium.title, "页面打开失败"
然后,去运行查看百度是否打开,这里展示运行后的效果:

这里就表明,该用例测试成功。
除了上面的展示,这里你还可以随便更改网站,来测试其他效果。

这是知网,当将网站更换为知网时,也能正常打开,并且控制台也会提示一些信息,如下图所示:

这是正确的。
除了上面展示的内容,这里还能做一些其他的复杂操作,比如:元素定位、元素交互、截图以及文件上传等。
如果你现在对selenium的掌握没有那么深,那么你还可以使用另一种方法来实现同样的效果(没有安装selenium的情况下)。
直接在项目中输入这段代码:
python
@pytest.fixture()
def selenium():
d = webdriver.Chrome()
yield d
d.quit()
输入这段代码,就类似实现了相同selenium插件的功能了,运行效果是一样的,可以自行实践。
以上就是这几天的学习内容啦,下一章内容准备写有关pytest的接口自动化封装实战,可以浅浅期待一下。
笔记整理不易,希望点个关注支持一下(* ̄︶ ̄)。

