Pytest:
注:本文内容较长,建议收藏/订阅后慢慢学习
目录:
- 前言
- Pytest介绍
- 特点
- 安装
- 查看版本
- 第一个脚本
- pytest运行规则
- 以类的形式编写case
- 命名规则
- 运行多条用例
- fixTure:测试装置介绍(前置、后置条件、装饰器)
- 常用命令行参数
- Mark:标记测试用例
- Mark:跳过(skip)及预期失败(xFail)
- Mark:参数化
前言:
- 自动化测试前:需要提前准备好测试数据,测试完成后,需要自动清里测试脏数据,有没有更好用的框架?
- 自动化测试中:需要使用多套测试数据实现用例的参数化,有没有更便捷的方式?
- 自动化测试后:需要自动生成优雅,简洁的测试报告,有没有更好的生成办法?
Pytest:
- pytest能够支持简单的单元测试和复杂的功能测试;
- pytest可以结合requests实现接口测试,结合Selenium,appium实现自动化功能测试。
- 使用pytest结合Allure集成到jekins中可以实现持续集成。
- pytest支持315种以上插件。
特点:
pytest为python的第三方单元测试库,需额外安装。它是一个非常成熟的全功能的python测试框架,主要有以下几个特点:
- 简单灵活,容易上手。
- 支持参数化。
- 能够支持简单的单元测试和复杂的功能测试。
- pytest具有很多第三方插件,并且可以自定义扩展。
- 执行测试过程中可以将某些测试跳过(skip),或者对某些预期失败的case标记成失败。
- 支持重复执行(rerun)失败的case。
- 方便的和持续集成工具jenkins集成。
- 可支持执行部分用例
安装:
1 | pip install -U pytest |
查看版本:
1 | pytest --version |
第一个脚本:
新建一个test_demo.py文件,写入如下代码:
1 | def test_answer(): |
打开cmd 进入 test_demo.py 文件所在文件夹,输入 pytest 或者 pytest test_demo.py,结果如下:
1 | ================================================= test session starts ================================================= |
pytest运行规则:
pytest运行规则:查找当前目录及其子目录下以test_*.py或*_test.py文件,找到文件后,在文件中找到以test开头函数并执行
以类的形式编写case:
上面是一个测试函数,当case较多的情况就不太合适了,我们可以把case写在类里面。
新建一个 test_demoClass.py文件,编写如下的代码:
1 | import pytest |
运行该类,结果如下:
1 | Testing started at 18:42 ... |
命名规则:
类型 | 规则 |
---|---|
文件名 | test_开头或者_test结尾 |
方法 | test_开头 |
类 | Test开头 |
注:测试类种不可用__init__构造函数
运行多条用例:
- 运行包下所有用例:pytest/py.test [包名]
- 单独运行一个pytest模块:pytest 文件名.py
- 运行某个模块里的某个类:pytest 文件夹.py::类名
- 运行某个模块里面某个类的某个方法: pytest 文件名.py::类名::方法名:
示例:
我们在项目目录中分别创建两个py文件并复制如下代码:
test_sample.py
1 | #!/usr/bin/env python3 |
test_sample2.py
1 | #!/usr/bin/env python3 |
打开cmd,进入项目目录中执行命令
命令: (运行包下所有用例:pytest/py.test [包名])
1 | pytest |
输出:
1 | :\study\test20\test_pytest_demo>pytest |
可以看到里面有一段这样的内容
1 | test_sample.py .F.F [ 80%] |
当我们执行pytest命令时,test_sample.py 和 test_sample2.py文件都被执行了
命令:(单独运行一个pytest模块:pytest 文件名.py)
1 | pytest test_sample2.py |
输出:
1 | =============================== test session starts =============================== |
可以看到只执行了test_sample2.py 文件中的case
命令:(运行某个模块里的某个类,pytest 文件夹.py::类名)
1 | pytest test_sample.py::TestCase |
输出:
1 | ================================= test session starts ================================= |
可以看到只运行了test_samples.py的TestCase类里边的case;test_three运行通过,test_four运行失败
命令:(运行某个模块里面某个类的某个方法 pytest 文件名.py::类名::方法名:)
1 | pytest test_sample.py::TestCase::test_four |
输出:
1 | ===================================== test session starts ================================ |
可以看到只执行了 test_sample.py->TestClass->test_four 这一条case
fixTure
测试装置介绍(前置、后置条件、装饰器)
类型 | 规则 |
---|---|
setup_module/teardown_module | 全局模块级,模块始末,全局的(优先级最高) |
setup_function/teardown_function | 函数级/在类外,只对函数用例生效(不在类中) |
setup_class/teardown_class | 类级,只在类中前后运行一次(在类中) |
setup_method/teardown_method | 方法级、类中的每个方法执行前后,开始于方法始末(在类中) |
setup/teardown | 在类中,运行在调用方法前后(重点),只在类中前后运行一次(在类中) |
- 先看下 setup_function/teardown_function 与case的执行关系
创建测试文件test_setup_teardown.py,粘贴如下代码:
1 | #!/usr/bin/env python |
命令:(运行模块里面所有case, 注:[-vs] 参数,展示详细的执行过程)
1 | pytest test_steup_teardown.py -vs |
输出:
1 | ================================================= test session starts ================================================= |
分析:
可以看到,当执行 case test_case_first 之前,首先执行了 setup_function,输出了 资源准备:setup function,随后执行 case test_case_first,输出了 test case first ,最后执行了 teardown_function,输出了 资源消毁:teardown function。
接着又开始执行case test_case_second,和执行 test_case_first一样,先执行setup_function,其次执行case test_case_second,最后执行teardown_function
结论:
setup_function:在每一条case执行之前调用
teardown_function:在每一条case执行之后调用
- 再看下 setup_module/teardown_module 与setup_function/teardown_function 和case的执行关系
在测试文件中test_setup_teardown.py,粘贴如下代码:
1 | #!/usr/bin/env python |
命令:(运行模块里面所有case, 注:[-vs] 参数,展示详细的执行过程)
1 | pytest test_steup_teardown.py -vs |
输出:
1 | ====================================================== test session starts ====================================================== |
分析:
可以看到执行顺序为 setup_module->setup_function->test_case_first->teardown_function->setup_function->test_case_second->teardown_function->teardown_module
结论:
setup_module:全局模块级,模块最开始,全局的(优先级最高),类似于 unittest的 setUpClass
setup_function:在每一条case执行之前调用,类似于 unittest的 setUp
teardown_function:在每一条case执行之后调用,类似于 unittest的 tearDown
teardown_module:全局模块级,模块最末尾,全局的(优先级最高),类似于 unittest的 tearDownClass
Fixture在自动化中的应用场景
场景1:
测试用例执行时,有的用例需要登录才能执行,有的不需要登录,setup和teardown无法满足,fixture则可以,默认scope function
步骤:
- 导入pytest
- 在登录函数上面加上@pytest.fixture()
- 在需要使用的测试发方法中传入(登录函数名称),就先登录
- 不传入就不登录直接执行测试方法
演示:
新建test_fixture1.py文件,复制如下代码
1 | import pytest |
示例:
执行如下命令
1 | pytest -vs .\test_fixture1.py::test_order |
输出:
1 | collected 1 item |
说明:可以看到,在代码中给 login方法添加了@pytest.fixture()装饰器,
在测试用例test_order中添加参数login(与login名称要一致),执行test_order用例时自动先执行了login方法
场景2:
当与其他开发人员共同开发项目时,公共的模块要在大家都访问的到的地方
解决:
使用conftest.py模块进行共享,并且他可以放在不同的范围共享
前提:
- conftest文件名不能换
- 放在项目下是全局共享的地方
演示:
新建conftest.py文件,复制如下代码
1 | @pytest.fixure() |
新建test_fixure2.py,复制如下代码
1 | import pytest |
执行如下命令:
1 | pytest --vs test_fixure2.py |
输出:
1 | collected 1 item |
说明:可以看到,case仍旧可以执行
Fixture用法总结:
- 模拟setup/teardown(一个用例可以引用d多个fixture)
- yield用法
- 作用域(session,module,class,function)
1
2
3
4
5取值 范围 说明
function 函数级 每一个函数或方法都会调用
class 类级别 每个测试类只运行一次
module 模块级 每一个.py文件调用一次
session 会话级 每次会话只需要运行一次,会话内所有方法及类,模块都共享这个方法 - 自动执行(autouse=True)
- conftest.py用法,一般会把fixture写在conftest.py文件中(名字不能改,必须为conftest)
常用命令行参数:
参数 | 含义 |
---|---|
–help | 帮助,用来查看参数 |
-x | 用例一旦失败(fail/error) 就立即停止执行 |
–maxfail=num | 用例用例失败数达到多少时停止执行 |
-m | 标记用例(重要) |
-k | 执行包含某个关键字的测试用例 |
-v | 打印详细日志 |
-s | 打印输出日志(通常-vs一起使用) |
–collect-only | 收集用例不执行(测试平台,pytest自动导入功能) |
–lf(–last-failed) | 只重新运行故障用例 |
–ff(–failed-first) | 先运行故障用例 再运行其它用例测试 |
演示:
新建 test_pytest.py文件,复制下面代码:
1 |
|
- help:帮助
命令行执行如下命令
示例:
1 | pytest --help |
输出:
1 | usage: pytest [options] [file_or_dir] [file_or_dir] [...] |
- x:用例一旦失败(fail/error) 就立即停止执行
命令行执行首先执行如下命令,运行所有case
示例:1
pytest -vs .\test_pytest.py
输出:
1 | collected 5 items |
说明:可以看到执行了模块内所有测试用例,3 failed, 2 passed。
- –lf:只重新运行故障用例
命令行执行执行如下命令,运行所有case
示例:1
pytest -vs .\test_pytest.py --lf
输出:
1 | collected 5 items / 2 deselected / 3 selected |
说明:可以看到只运行了失败的用例
- –ff:先运行故障用例 再运行其它用例测试
命令行执行执行如下命令,运行所有case
示例:
1 | pytest -vs .\test_pytest.py --ff |
输出:
1 | collected 5 items |
说明:可以看到先运行了故障用例,再运行了其它用例
命令行执行执行如下命令,运行所有case
示例:
1 | pytest -vs .\test_pytest.py -x |
输出:
1 | ollected 5 items |
说明:可以看到,当运行到第一条错误case时便停止继续运行了,stopping after 1 failures/1 failed in 0.04s
- –maxfail=num:用例用例失败数达到多少时停止执行(num:失败的用例数)
命令行执行执行如下命令,运行所有case
示例:
1 | pytest -vs .\test_pytest.py --maxfail=2 |
输出:
1 | collected 5 items |
说明:–maxfail=2,参数设置了错误case数为4,可以看到当错误case数达到2条时便停止了执行(stopping after 2 failures /2 failed in 0.04s)
-m:标记用例(重点)
该参数用法较复杂,后面单独介绍-k:执行包含某个关键字的测试用例
命令行执行执行如下命令,运行所有case
示例:1
pytest -vs .\test_pytest.py -k "sum"
输出:
1 | collected 5 items / 3 deselected / 2 selected |
说明:可以看到 只执行了带有”sum”关键字的case
Mark标记测试用例
- 场景:只执行 符合要求的某一部分用例,可以把一个web项目划分多个模块,然后制定模块名称执行
- 解决:在测试用例方法上添加@pytest.mark.标签名
- 执行:-m 参数执行自定义标签的相关用例
1 | pytest -s test_mark_demo.py -m=int |
示例:
新建test_mark_demo.py文件,复制如下代码
1 | #!/usr/bin/env python3 |
示例:执行如下命令
1 | pytest -vs .\test_mark_demo.py -m=str |
输出:
1 | collected 8 items / 6 deselected / 2 selected |
说明:可以看到只执行了2条标记有 str 关键字的case;除此之外还存在8条警告,出现警告的原因是没有注册标签;
新建一个pytest.ini文件,复制如下内容注册标签,然后再执行,就不会再出现警告
1 | [pytest] |
Mark跳过测试用例以及预期失败
- 这是pytest的内置标签,可以处理一些特殊的测试用例,不能成功的测试用例
- skip:始终跳过该测试用例
- skipif:遇见特定情况跳过该测试用例
- xFail:遇见特定情况,产生一个”期望失败”输出
解决1:添加装饰器
1 | @pytest.mark.skip |
解决2:代码中添加跳过代码
1 | @pytest.skip(reason) |
示例:
新建test_skip.py文件,复制如下代码
1 | import pytest |
示例:执行如下命令
1 | pytest -vs .\test_skip.py |
输出:
1 | collecting ... win32 |
参数化
参数化设计方法就是将模型中的定量信息变量化,使之成为任意调整的参数。
对于变量化参数赋予不同数值,就可得到不同大小和形状的零件模型。
mark参数化测试函数的使用
语法:
1 | @pytest.mark.parametrize(argnames,argvalues) |
- 单参数
- 多参数
- 用例重命名:通过ids参数实现
- 笛卡尔积:适用于数据组合情况
演示:新建test_mark_parmes.py,复制如下代码
1 | #!/usr/bin/env python3 |
示例1:
运行单参数case,执行如下命令
1 | pytest -vs .\test_mark_parames.py::test_search |
输出:
1 | collected 3 items |
示例2:
运行多参数case并为case重命名,执行如下命令
1 | pytest -vs .\test_mark_parames.py::test_mark_more |
输出:
1 | collected 3 items |
示例2:
运行笛卡尔积case,执行如下命令
1 | pytest -vs .\test_mark_parames.py::test_dkej |
输出:
1 | collected 9 items |
使用yaml文件进行参数化
yaml安装:
pycharm编译器打开settings->project->python interpreter,点击依赖包旁的’+’加号,搜索pyyaml
选择”PyYAML”(注意字母大小写,别装错了),点击下方install package
yaml基本用法:
yaml实现list
1
2
3
4list:
- 10
- 20
- 30yaml实现字典
1
2
3
4dict:
by:id
locator:name
action:clickyaml实现嵌套
1 | - |
- 加载yaml文件
1
yaml.safe_load(open(filepath))
代码演示:
创建data.yaml文件,复制如下内容
1 | - |
创建test_yaml.py文件,复制如下代码
1 | import pytest |
示例:
执行如下命令,运行case
1 | pytest -vs test_yaml.py |
输出:
1 | collected 3 items |
异常处理
- try…except…
- pytest.raaises()
示例代码:
新建test_raises.py,复制如下代码
1 | import pytest |
数据驱动
数据驱动就是数据的改变从而驱动自动化测试的执行,最终引起测试结果的改变。简单来说,就是参数化的应用。
数据量小的测试用例可以使用代码的参数化来实现数据驱动,数据量大的情况下建议大家使用一种结构化的文件(如yaml,json等)来
对数据进行存储,然后再测试用例中读取这些数据。
应用场景:
- App/Web/接口自动化测试
- 测试步骤的数据驱动
- 测试数据的数据驱动
- 配置的数据驱动
Allure测试框架
- allure介绍
- allure安装
- Allure特性分析
- Allure运行
- Allure报告中嵌入文本、图片、视频等资源
介绍:
allure是一个轻量级、灵活的,支持多语言的测试报告工具
多平台的,奢华的report框架
可以为dev/qa提供详尽的测试报告,测试步骤,log等
也可以为管理层提供high level统计报告
Java语言开发的,支持pytest,JavaScript,PHP,ruby等
可以集成到Jenkins
allure常用特性:
场景:
希望在报告中看到测试功能,子功能或场景,测试步骤,包括测试附加信息
解决:
1 | @Feature,@story,@step,@attach |
步骤:
1 | import allure |
安装:
1 | pip install allure-pytest |
运行:
在执行测试期间收集结果
1 | pytest [测试文件] -s -q --alluredir=./result/(指定存储目录) |
查看测试报告:
方式一:测试完后查看实际报告,在线报告,会直接打开默认浏览器展示当前报告
1 | allure serve ./result/ |
方式二:从结果生成报告,启动tomact服务,需要两个步骤,生成报告,打开报告
生成报告:
1
2allure generate ./result/ -o ./report/ --clean(注意:覆盖路径加 --clean)
打开报告:
1
allure open -h 127.0.0.1 -p 8883 ./report/
pytest插件开发
pytest插件分类
外部插件:
1
pip install 安装的插件
本地插件:
1
pytest自动模块发现机制(conftest.py存放的)
内置插件:
1
代码内部的 _pytest目录加载
pytest插件介绍
常用插件
1 | pip install pytest-ordering 控制用例执行顺序(重点) |
pytest-ordering 控制用例执行顺序:
场景:
对于集成测试,经常会有上下文依赖关系的测试用例,比如10个步骤,拆成10条case,这时候需要能知道到底执行到
哪步报错
用例默认执行顺序:自上二而下执行
解决:
可以通过 setup/teardown 和 fixture解决,也可以使用插件解决
安装:
1 | pip install pytest-ordering |
用法:
1 | @pytest.mark.run(order=2) |
注意:多个插件装饰器(>2)时,有可能会发生冲突
pytest-xdist 分布式并发执行测试用例:
场景1:
测试用例1000条,1个用例执行1分钟,一个测试人员需要1000分钟。
通常我们会用人力成本换取时间成本,加几个人一起执行,时间就会缩短。
如果10个人执行只需要100分钟,这就是一种分布式场景
场景2:
假设有个报名系统,对报名总数统计,数据同时进行修改操作时可能出现问题,
需要模拟这个场景,需要多用户并发请求数据。
解决:
使用分布式并发执行测试用例,分布式插件,pytest-xdist
安装:
1 | pip install pytest-xdist |
注意:用例多的时候效果明显,多进程并发执行,同时支持allure
使用:
1 | pytest -n 4 |
pytest hook执行顺序
待补充
pytest配置文件
待补充
log日志模块
待补充
持续补充ing~
。。。
。。。