Pytest 自动化测试框架速通指南(二)

文章摘要

本文作为上篇 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,在浏览器打开,就可以看到可视化的测试用例展示。如下图:

小贴士:你有没有注意到这个前端展示是英文的呀,如果你是小白,想要使用中文来学习,那么你可以使用这个命令在终端输入,就能转换为中文。

python 复制代码
allure generate temps -c -o report --report-language zh

如果还想用英文还能转换回来,使用这个命令:

复制代码
 allure generate temps -c -o report --report-language en
python 复制代码
 allure 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

  1. 搜索关于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的接口自动化封装实战,可以浅浅期待一下。

笔记整理不易,希望点个关注支持一下(* ̄︶ ̄)。

相关推荐
天才测试猿21 小时前
实例介绍:Unittest框架及自动化测试实现流程
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
Logintern091 天前
pytest的AST 断言重写
pytest
Tinyfacture2 天前
接口自动化之添加商品(pytest)
python·测试工具·自动化·pytest
程序员三藏3 天前
自动化测试详解
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
ji_shuke4 天前
从零深入:基于 Playwright + Pytest + Allure 的企业级 Web 端到端自动化测试框架实战
前端·自动化测试·docker·jenkins·pytest·allure·playwright
降临-max4 天前
Postman----接口自动化
软件测试·功能测试·自动化·postman
测试秃头怪4 天前
postman接口测试详解
自动化测试·软件测试·python·测试工具·测试用例·接口测试·postman