当前位置: 首页 > news >正文

Pytest--安装与入门

pytest是一个能够简化成测试系统构建、方便测试规模扩展的框架,它让测试变得更具表现力和可读性–模版代码不再是必需的。只需要几分钟的时间,就可以对你的应用开始一个简单的单元测试或者复杂的功能测试。

1. 安装pytest

pip install -U pytest

检查版本

> pytest --version
pytest 8.2.2

2. 创建第一个测试

注:

  • 文件名必须以 test 开头
  • 测试类必须以 Test 开头,且不能含有 init 方法
  • 测试方法必须以 test 开头
# test_sample.py
def func(x):return x + 1def test_answer():assert func(3) == 5

然后在该python文件的目录下执行pytest

================================================= test session starts =================================================
platform win32 -- Python 3.9.9, pytest-7.0.1, pluggy-1.0.0
rootdir: D:\Code\Pytest
collected 1 itemtest_sample.py F                                                                                                 [100%]====================================================== FAILURES =======================================================
_____________________________________________________ test_answer _____________________________________________________def test_answer():
>       assert func(3) == 5
E       assert 4 == 5
E        +  where 4 = func(3)test_sample.py:5: AssertionError
=============================================== short test summary info ===============================================
FAILED test_sample.py::test_answer - assert 4 == 5
================================================== 1 failed in 0.12s ==================================================
PS D:\Code\Pytest>

[100%]指的是运行所有测试用例的总体进度。完成后,pytest会显示一个报告,如上述测试,是一个失败报告,因为func(3)不返回5。

3. 运行多个测试

pytest _*.py或者pytest *_可以使 pytest 运行目录下的多个符合条件的文件。

3. pytest测试用例的运行方式

主函数模式

1. 运行所有:pytest.main()
import pytestdef fun_plus(x):return x+2def test_answer():assert fun_plus(2) == 5def test_addition():assert 1+1 == 2if __name__ == '__main__':pytest.main()

执行结果

测试用例执行通过是没有的展示的,但执行失败会有具体的信息,甚至指出出错地方:

F:\SoftWare\Python\Python39\python39.exe F:/SoftWare/JetBrains/PyCharm2023.1.2/plugins/python/helpers/pycharm/_jb_pytest_runner.py --path F:\Code\PyCharmProject\Interview\pytest\test_demo01.py 
Testing started at 10:09 ...
Launching pytest with arguments F:\Code\PyCharmProject\Interview\pytest\test_demo01.py --no-header --no-summary -q in F:\Code\PyCharmProject\Interview\pytest============================= test session starts =============================
collecting ... collected 2 itemstest_demo01.py::test_answer FAILED                                       [ 50%]
test_demo01.py:5 (test_answer)
4 != 5Expected :5
Actual   :4
<Click to see difference>def test_answer():
>       assert fun_plus(2) == 5
E       assert 4 == 5
E        +  where 4 = fun_plus(2)test_demo01.py:7: AssertionErrortest_demo01.py::test_addition PASSED                                     [100%]========================= 1 failed, 1 passed in 0.03s =========================Process finished with exit code 1
2. 指定模块/文件
# test_demo01.py
import pytestdef fun_plus(x):return x+2def test_answer():assert fun_plus(2) == 5def test_addition():assert 1+1 == 2# if __name__ == '__main__':
#     pytest.main()
# test_demo02.py
import pytestdef fun_minus(x):return x-2def test_answer():assert fun_minus(2) == 5def test_minus():assert 4-2 == 2# if __name__ == '__main__':
#     pytest.main()
# run_suite.py
import pytestif __name__ == '__main__':pytest.main(['-vs', './test_demo01.py', './test_demo02.py'])
参数详解:

-s:表⽰输出调试信息,输出print信息
-v:显⽰更加详细的信息
-vs:两个参数可以同时使⽤

注:main函数中的参数要求是列表形式的,如果有多个模块/文件,则继续以逗号分隔

多线程或者分布式运行:

安装插件 pytest-xdist

pip install pytest-xdist
# run_suite.py
import pytestif __name__ == '__main__':pytest.main(['-vs', './', '-n 2'])
# 以两个线程来运行当前目录下的所有测试用例

执行结果:

============================= test session starts =============================
platform win32 -- Python 3.9.9, pytest-8.2.2, pluggy-1.5.0 -- F:\SoftWare\Python\Python39\python39.exe
cachedir: .pytest_cache
rootdir: F:\Code\PyCharmProject\Interview\pytest
plugins: xdist-3.6.1
created: 2/2 workers
2 workers [4 items]scheduling tests via LoadSchedulingtest_demo02.py::test_answer 
test_demo01.py::test_answer 
[gw0] FAILED test_demo01.py::test_answer 
[gw1] FAILED test_demo02.py::test_answer 
test_demo02.py::test_minus 
[gw1] PASSED test_demo02.py::test_minus 
test_demo01.py::test_addition 
[gw0] PASSED test_demo01.py::test_addition ================================== FAILURES ===================================
_________________________________ test_answer _________________________________
[gw0] win32 -- Python 3.9.9 F:\SoftWare\Python\Python39\python39.exedef test_answer():
>       assert fun_plus(2) == 5
E       assert 4 == 5
E        +  where 4 = fun_plus(2)test_demo01.py:7: AssertionError
_________________________________ test_answer _________________________________
[gw1] win32 -- Python 3.9.9 F:\SoftWare\Python\Python39\python39.exedef test_answer():
>       assert fun_minus(2) == 5
E       assert 0 == 5
E        +  where 0 = fun_minus(2)test_demo02.py:7: AssertionError
=========================== short test summary info ===========================
FAILED test_demo01.py::test_answer - assert 4 == 5
FAILED test_demo02.py::test_answer - assert 0 == 5
========================= 2 failed, 2 passed in 0.34s =========================Process finished with exit code 0
reruns 失败用例重跑

安装插件 pytest-rerunfailures

pip install pytest-rerunfailures

–reruns=num:失败用例重跑,将这个模块多执行num次,最后返回结果

# run_suite.py
import pytestif __name__ == '__main__':pytest.main(['-vs', '--reruns=2'])

执行结果:

============================= test session starts =============================
platform win32 -- Python 3.9.9, pytest-8.2.2, pluggy-1.5.0 -- F:\SoftWare\Python\Python39\python39.exe
cachedir: .pytest_cache
rootdir: F:\Code\PyCharmProject\Interview\pytest
plugins: rerunfailures-14.0, xdist-3.6.1
collecting ... collected 4 itemstest_demo01.py::test_answer RERUN
test_demo01.py::test_answer RERUN
test_demo01.py::test_answer FAILED
test_demo01.py::test_addition PASSED
test_demo02.py::test_answer RERUN
test_demo02.py::test_answer RERUN
test_demo02.py::test_answer FAILED
test_demo02.py::test_minus PASSED================================== FAILURES ===================================
_________________________________ test_answer _________________________________def test_answer():
>       assert fun_plus(2) == 5
E       assert 4 == 5
E        +  where 4 = fun_plus(2)test_demo01.py:7: AssertionError
_________________________________ test_answer _________________________________def test_answer():
>       assert fun_minus(2) == 5
E       assert 0 == 5
E        +  where 0 = fun_minus(2)test_demo02.py:7: AssertionError
=========================== short test summary info ===========================
FAILED test_demo01.py::test_answer - assert 4 == 5
FAILED test_demo02.py::test_answer - assert 0 == 5
==================== 2 failed, 2 passed, 4 rerun in 0.05s =====================Process finished with exit code 0
用例失败,测试停止

-x:只要有一个用例失败,测试就会停止

# run_suite.py
import pytestif __name__ == '__main__':pytest.main(['-vs', '-x'])

执行结果:

============================= test session starts =============================
platform win32 -- Python 3.9.9, pytest-8.2.2, pluggy-1.5.0 -- F:\SoftWare\Python\Python39\python39.exe
cachedir: .pytest_cache
rootdir: F:\Code\PyCharmProject\Interview\pytest
plugins: rerunfailures-14.0, xdist-3.6.1
collecting ... collected 4 itemstest_demo01.py::test_answer FAILED================================== FAILURES ===================================
_________________________________ test_answer _________________________________def test_answer():
>       assert fun_plus(2) == 5
E       assert 4 == 5
E        +  where 4 = fun_plus(2)test_demo01.py:7: AssertionError
=========================== short test summary info ===========================
FAILED test_demo01.py::test_answer - assert 4 == 5
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!
============================== 1 failed in 0.04s ==============================Process finished with exit code 0
最大失败测试用例

–maxfail=n:如果有n个用例失败,测试就会停止(前提:安装插件 pytest-xdist)

# run_suite.py
import pytestif __name__ == '__main__':pytest.main(['-vs', '--maxfail=1'])

执行结果:

============================= test session starts =============================
platform win32 -- Python 3.9.9, pytest-8.2.2, pluggy-1.5.0 -- F:\SoftWare\Python\Python39\python39.exe
cachedir: .pytest_cache
rootdir: F:\Code\PyCharmProject\Interview\pytest
plugins: rerunfailures-14.0, xdist-3.6.1
collecting ... collected 4 itemstest_demo01.py::test_answer FAILED================================== FAILURES ===================================
_________________________________ test_answer _________________________________def test_answer():
>       assert fun_plus(2) == 5
E       assert 4 == 5
E        +  where 4 = fun_plus(2)test_demo01.py:7: AssertionError
=========================== short test summary info ===========================
FAILED test_demo01.py::test_answer - assert 4 == 5
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!
============================== 1 failed in 0.04s ==============================Process finished with exit code 0
通过读取 pytest.ini 配置文件运行
# pytest.ini[pytest]
# 命令行参数,用空格分隔
addopts = -vs# 测试用例文件夹
testpaths = testcase
# run_suite.py
import pytestif __name__ == '__main__':pytest.main(['--maxfail=1'])

已经将测试用例转移到 testcase 文件夹下,看看执行结果:

============================= test session starts =============================
platform win32 -- Python 3.9.9, pytest-8.2.2, pluggy-1.5.0 -- F:\SoftWare\Python\Python39\python39.exe
cachedir: .pytest_cache
rootdir: F:\Code\PyCharmProject\Interview\pytest
configfile: pytest.ini
testpaths: testcase
plugins: rerunfailures-14.0, xdist-3.6.1
collecting ... collected 4 itemstestcase/test_demo01.py::test_answer FAILED================================== FAILURES ===================================
_________________________________ test_answer _________________________________def test_answer():
>       assert fun_plus(2) == 5
E       assert 4 == 5
E        +  where 4 = fun_plus(2)testcase\test_demo01.py:7: AssertionError
=========================== short test summary info ===========================
FAILED testcase/test_demo01.py::test_answer - assert 4 == 5
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!
============================== 1 failed in 0.04s ==============================Process finished with exit code 0

更多的配置还有:


# 配置测试搜索的模块文件名称
python_files = test_*.py# 配置测试搜索的测试类名
python_classes = Test*# 配置测试搜索的函数名
python_functions = test*

4. pytest执行测试用例顺序

unittest默认的执行顺序:

按照ASCII大小执行的,即在写测试用例时将测试名按大小顺序或加上数字顺序大小即可使其按顺序执行。

pytest默认的执行顺序:

按照用例的先后顺序执行,即哪个用例写在前面就先执行哪个用例

当然我们也可以通过插件的方式自定义其执行顺序

安装 pytest-ordering 插件

pip install pytest-ordering

使用方法

@pytest.mark.run(order=1)

import pytestdef fun_plus(x):return x+2def test_01_answer():assert fun_plus(2) == 5@pytest.mark.run(order=1)
def test_02_addition():assert 1+1 == 2if __name__ == '__main__':pytest.main()

5. 以安静报告模式执行测试用例

pytest -q test_sysexit.py

注:-q与--quiet的效果一样。

6. 分组执行测试用例

一旦开发了多个测试,你可能需要对测试进行分组,我们可以利用配置文件中的配置为测试进行分组执行:

@pytest.mark.组名

# pytest.ini
[pytest]
# 命令行参数,用空格分隔
addopts = -vs# 测试用例文件夹
testpaths = ./testcase# 分组
markers =smoke:冒烟用例group1:第一组测试用例
# test_demo02.py
import pytestdef fun_minus(x):return x-2def test_answer():assert fun_minus(2) == 5@pytest.mark.smoke
def test_minus():assert 4-2 == 2if __name__ == '__main__':pytest.main(['./test_demo02.py', '-m', 'smoke'])

测试结果:

============================= test session starts =============================
platform win32 -- Python 3.9.9, pytest-8.2.2, pluggy-1.5.0 -- F:\SoftWare\Python\Python39\python39.exe
cachedir: .pytest_cache
rootdir: F:\Code\PyCharmProject\Interview\pytest
configfile: pytest.ini
plugins: ordering-0.6, rerunfailures-14.0, xdist-3.6.1
collecting ... collected 2 items / 1 deselected / 1 selectedtest_demo02.py::test_minus PASSED======================= 1 passed, 1 deselected in 0.02s =======================Process finished with exit code 0

记一个PyCharm中可能遇到的问题

在单个test_xxx.py文件中,在main中传入了参数,但不管怎么运行都没有生效,在cmd窗口又是正常生效的,甚至在run_suite.py中的main也是正常的。这是因为程序自动识别到了pytest框架,默认以pytest运行,要main主函数运行。

解决方法:

1、修改Python解释器(但需要对每个test文件都这样,很麻烦)

Edit Configurations,新增解释器,将目标文件作为单独的python文件运行

2、修改Python integrated Tools(可以一劳永逸)

进入到File->Settings->Tools->Python integrated Tools页面,找到 Testing - Default test runner,将其修改为Unittest

相关文章:

  • Firewalld 防火墙基础
  • Flask-Session使用Redis
  • 蓝桥杯web组国三选手题纲解析和备赛技巧--经验分享
  • c++之旅第十一弹——顺序表
  • 常见网络攻击方式及防御方法
  • 图像处理中的二维傅里叶变换
  • 鸿蒙:1.入门
  • 十大排序:插入/希尔/选择/堆/冒泡/快速/归并/计数/基数/桶排序 汇总(C语言)
  • 【收藏级神丹】Liae384_刘亦菲_直播可用,平衡度最高的原创神丹,独家珍稀资源
  • Kafka集群安装部署
  • 嵌入式linux sqlite3读写demo
  • 【面试题】网络IO模型
  • 从0开始学习pyspark--Spark DataFrame数据的选取与访问[第5节]
  • jmeter-beanshell学习1-vars使用获取变量和设置变量
  • go内存返还系统相关代码
  • 【mysql】环境安装、服务启动、密码设置
  • C++入门教程(10):for 语句
  • ERLANG 网工修炼笔记 ---- UDP
  • Git的一些常用操作
  • java中具有继承关系的类及其对象初始化顺序
  • Koa2 之文件上传下载
  • PHP那些事儿
  • Python连接Oracle
  • WePY 在小程序性能调优上做出的探究
  • Zepto.js源码学习之二
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 包装类对象
  • 从tcpdump抓包看TCP/IP协议
  • 订阅Forge Viewer所有的事件
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 如何在GitHub上创建个人博客
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • 再谈express与koa的对比
  • 终端用户监控:真实用户监控还是模拟监控?
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • # 20155222 2016-2017-2 《Java程序设计》第5周学习总结
  • #数据结构 笔记一
  • $.ajax()方法详解
  • ( )的作用是将计算机中的信息传送给用户,计算机应用基础 吉大15春学期《计算机应用基础》在线作业二及答案...
  • (5)STL算法之复制
  • (9)STL算法之逆转旋转
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (保姆级教程)Mysql中索引、触发器、存储过程、存储函数的概念、作用,以及如何使用索引、存储过程,代码操作演示
  • (附源码)springboot助农电商系统 毕业设计 081919
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (三分钟)速览传统边缘检测算子
  • (实战)静默dbca安装创建数据库 --参数说明+举例
  • (四)事件系统
  • (转)Windows2003安全设置/维护
  • .mysql secret在哪_MYSQL基本操作(上)
  • .net mvc部分视图
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .net开发时的诡异问题,button的onclick事件无效