pytest介绍

  • pytest是一个非常成熟的全功能的Python测试框架。

    • 简单灵活,容易上手
    • 支持参数化
    • 测试用例的skip和xfail,自动失败重试等处理
    • 能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试,接口自动化测试(pytest+requests)
    • pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-allure(完美html测试报告生成),pytest-xdist(多CPU并发)等
    • 可以很好的和jenkins集成
  • 文档:http://docs.pytest.org/en/latest/contents.html#toc
  • 第三方库:https://pypi.org/search/?q=pytest
  • Github地址:https://github.com/pytest-dev/pytest/

pytest安装与依赖

依赖

pytest requires: Python 3.7+ or PyPy3.

安装

 # 安装pytest:pip install pytest# 升级pytestpip install -U pytest# 查看pytest版本
pytest --version# 查看已安装包列表
pip list# 查看pytest帮助文档
pytest -h# 安装第三方插件pip install pytest-sugarpip install pytest-rerunfailurespip install pytest-xdistpip install pytest-assumepip install pytest-html

pytest测试用例的识别与运行

  1. 发现用例的规则
    a) 文件test_.py开头和_test.py结尾
    b) Test开头的类中test开头的方法(测试类不能带有__init__方法)
    c) 模块中test开头的函数(可以不在class中)

注意点:
pytest是以方法为单位发现用例的,你写不写测试类根本不重要
在哪个目录下执行pytest就在哪个目录下按照上述规则去查找

  1. 自定义查找规则:pytest.ini

  2. 用例执行顺序

    • Unittest用例执行顺序(pytest可以执行unittest框架写的用例和方法)
    • 根据ASCII码来排序
    • Pytest用例执行顺序
    • 文件名称按ASCII码排序
    • 文件内根据定义的方法的先后顺序,从上到下执行

参数解析

  • pytest / py.test
  • 打印详细运行日志信息:pytest -v (最高级别信息-verbose)
  • s是带控制台输出结果,也是输出详细,可以打印测试用例中print的输出:pytest -v -s 文件名
  • 执行单独一个pytest模块:pytest 文件名.py
  • 运行某个模块里面某个类:pytest 文件名.py::类名
  • 运行某个模块里面某个类里面的方法:pytest 文件名.py::类名::方法名
  • 跳过某个用例:pytest -k "类名 and not 方法名",如pytest -k "TestDemo and not test_one"
  • 运行带有某标记的测试用例(pytest.mark.标记名):pytest -m 标记名
  • 一旦运行到报错就停止运行:pytest -x 文件名
  • 当错误达到num的时候就停止运行:pytest --maxfile=[num]

pycharm配置与执行pytest

运行方式:pytest.main([“-v”, “TestDemo”]) (所有的参数和pytest命令行方式是一样的)

pytest框架结构

import pytest类似的setup,teardown同样更灵活
- 模块级别(setup_module / teardown_module)模块始末,全局的(优先最高)
- 函数级(setup_function / teardown_function)只对函数用例生效 (不在类中)
- 类级 (setup_class / teardown_class)只在类中前后运行一次 (在类中)
- 方法级 (setup_method / teardown_method)开始于方法始末 (在类中)
- 类里面 (setup / teardown)运行在调用方法的前后

演示代码:

import pytestdef setup_module():print("这是一个setup_module")def teardown_module():print("这是一个teardown_module")def setup_function():print("这是一个setup_function")def teardown_function():print("这是一个teardown_function")def test_login():print("这是一个外部的方法")assert "admin" == "admin"class TestDemo:def setup_class(self):print("这是一个setup_class")def teardown_class(self):print("这是一个teardown_class")def setup(self):print("这是一个setup")def teardown(self):print("这是一个teardown")def test_a(self):assert 2 == 2def test_b(self):assert 3 == 3def test_c(self):assert 5 == 5if __name__ == '__main__':pytest.main()

运行结果:

pytest实战

失败重新运行

场景:测试失败后要重新运行n次,要在重新运行之间添加延迟时间,间隔n秒再运行。

安装pip install pytest-rerunfailures

执行
- 测试失败后重新运行3次:pytest --reruns 3 -v -s test_class.py
- 测试失败后重新运行5次且每次重新运行间隔1秒:pytest -v --reruns 5 --reruns-delay 1

代码:

import pytestclass TestDemo:def test_a(self):assert 1 == 2def test_b(self):assert 3 == 3def test_c(self):assert 5 == 5if __name__ == '__main__':pytest.main()

运行结果:

多条断言有失败也都运行

场景:一个方法中写多条断言,通常第一条断言失败,下面的断言也不执行了。但是我们希望即使第一条断言失败,后续断言还是继续执行。

安装pip install pytest-assume

执行pytest.assume(断言表达式), 如:pytest.assume(2==4)

代码:

import pytestclass TestDemo:def test_a(self):pytest.assume(1 == 2)pytest.assume(2 == 2)pytest.assume(1 == 2)if __name__ == '__main__':pytest.main()

运行结果:

pytest-fixture的用法

场景:测试用例执行时,有的用例需要登录才能执行,有的用例不需要登录。这种场景setup与teardown无法满足,但是fixture可以。默认scope(范围)是function。

步骤:
- 导入pytest:import pytest
- 在登录的函数上面加上 @pytest.fixture()
- 在要使用的测试方法中传入(登录函数名称),就先登录
- 不传入的就不登录直接执行测试方法

代码:

import pytest@pytest.fixture()
def login():print("这是登录方法")def test_case1(login):print("test_case1")passdef test_case2():print("test_case2")passdef test_case3(login):print("test_case3")passif __name__ == '__main__':pytest.main(["-s"])

运行结果:

conftest的使用

conftest.py配置需要注意:
- conftest文件名是不能自定义的,不能更改
- conftest.py与运行的用例要在同一个package下,并且有__init__.py文件
- 不需要import导入conftest.py, pytest用例会自动查找
- 全局的配置和前期工作都可以写在这里,放在某个包下,就是这个包数据共享的地方

场景:当你与其他测试工程师合作一起开发时,公共模块要在不同文件中,要在大家都能访问到的地方。

解决:conftest.py这个文件进行数据共享,并且他可以放在不同位置起着不同的范围共享作用。

执行:系统执行到参数login时先从本文件中查找是否有这个名字的变量,之后再在conftest.py中查找是否有

步骤:将登录模块带有@pytest.fixture写在conftest.py

代码:
conftest.py

import pytest@pytest.fixture()
def login():print("这是登录方法")

test_main.py

import pytestdef test_case1(login):print("test_case1")passdef test_case2():print("test_case2")passdef test_case3(login):print("test_case3")passif __name__ == '__main__':pytest.main(["-s"])

运行结果:

yield关键字的使用

场景:你已经可以将测试方法前要执行的或依赖的解决了,测试方法后销毁清除数据的要如何进行呢?范围是模块级别的。类似setupClass。

解决:通过在同一个模块中加入yield关键字,yield是调用第一次返回结果,第二次执行它下面的语句返回。

步骤:

  • 在方法上加上@pytest.fixture(scope=module)
  • 在方法中加yield,之后加销毁清除的步骤
  • 注意:这种方式没有返回值,如果希望返回使用addfinalizer

代码:
conftest.py

import pytest# 作用域:module是在模块之前执行,模块之后执行
@pytest.fixture(scope="module")
def open():print("打开浏览器")yieldprint("执行teardown")print("关闭浏览器")

test_main.py

import pytestdef test_search1(open):print("test_search1")raise NameErrorpassdef test_search2(open):print("test_search2")passdef test_search3(open):print("test_search3")passif __name__ == '__main__':pytest.main(["-s"])

运行结果:
由于open方法是模块级别的,因此里面的前置后置方法在该测试模块test_main.py运行时均只执行一次。

fixture的自动应用

场景:不想原测试方法有任何改动,或全部都自动实现自动应用,没特例,也都不需要返回值时可以选择自动应用。

解决:使用fixture中参数autouse=True实现。

步骤
- 在方法上加上@pytest.fixture(autouse=True)
- 在测试方法上加@pytest.mark.usefixtures("start")

代码:
conftest.py

import pytest# 作用域:module是在模块之前执行,模块之后执行
@pytest.fixture(autouse=True)
def open():print("打开浏览器")yieldprint("执行teardown")print("关闭浏览器")

test_main.py

import pytestdef test_search1():print("test_search1")raise NameErrorpassdef test_search2():print("test_search2")passdef test_search3():print("test_search3")passif __name__ == '__main__':pytest.main(["-s"])

运行结果:

测试数据的传递parametrize

用法@pytest.mark.parametrize(“用例方法中接收的参数名”,数据)

场景:我们在测试过程中,涉及到测试数据的传递。

解决:使用@pytest.mark.parametrize()进行测试数据的传递。

代码:

import pytest@pytest.mark.parametrize("test_input, expected", [("3+5", 8), ("4+5", 8)])
def test_eval(test_input, expected):assert eval(test_input) == expected# 上面和下面这两种方法的结果是一样的@pytest.mark.parametrize("test_input", ["3+5", "4+5"])
@pytest.mark.parametrize("expected", [8, 8])
def test_eval2(test_input, expected):assert eval(test_input) == expectedif __name__ == '__main__':pytest.main(["-s"])

运行结果:

fixture带参数传递

场景:测试离不开数据,为了数据灵活,一般数据都是通过参数传的。

解决:fixture通过固定参数request传递。

步骤:在fixture中增加@pytest.fixture(params=[1,2,“linda”]),在方法参数中写request。

代码:
conftest.py

import pytest# 作用域:module是在模块之前执行,模块之后执行
@pytest.fixture(autouse=True)
def login_r(request):# 这里接收并传入参数user = request.paramprint(f"打开首页准备登录,登录用户:{user}")return user

test_main.py

import pytesttest_user_data = ["Tome", "Jerry"]# indirect=True可以把传递过来的参数当函数执行
@pytest.mark.parametrize("login_r", test_user_data, indirect=True)
def test_login(login_r):a = login_rprint(f"测试用例中login的返回值:{a}")assert a != ""if __name__ == '__main__':pytest.main(["-s"])

运行结果:

skip跳转测试用例

用法:
• @pytest.mark.skip pytest.mark.skip(*, reason=None)
• @pytest.mark.skipif pytest.mark.skipif(condition, *, reason=None)

使用场景:
- 调试时不想运行这个用例
- 标记无法在某些平台上运行的测试功能
- 在某些版本中执行,其他版本中跳过
- 当前外部资源不可用时跳过(如果测试数据是从数据库中获取的,连接数据库未成功则跳过-因为执行会报错)

代码:

import pytesta = 4
b = 3@pytest.mark.skipif(condition=a < b, reason="当a<b时,该用例跳过")
def test_case1():assert 1 == 2@pytest.mark.skipif(condition=a > b, reason="当a>b时,该用例跳过")
def test_case2():assert 1 == 2@pytest.mark.skip(reason="直接跳过")
def test_case3():assert 1 == 2if __name__ == '__main__':pytest.main(["-s"])

运行结果:

xfail标记用例为失败

用法pytest.mark.xfail(condition=None, *, reason=None, raises=None, run=True, strict=False)

使用场景:
- 功能测试尚未实施或尚未修复的错误,当测试通过时尽管预计会失败(标记为pytest.mark.xfail),它是一个xpass,将在测试摘要中报告。
- 你希望测试由于某种情况而就应该失败。

代码:

import pytestdef test_case1():assert 2 == 2@pytest.mark.xfail(reason="标记这个用例为失败")
def test_case2():assert 2 == 2def test_case3():assert 2 == 2if __name__ == '__main__':pytest.main(["-s"])

运行结果:

使用自定义标记mark只执行某部分用例

场景:
- 只执行符合要求的某一部分用例,可以把一个web项目划分多个模块,然后指定模块名称执行。
- APP自动化时,如果想Android和IOS公用同一套代码时,也可以使用标记功能,标明哪些是IOS的用例,哪些是Android的,运行代码时指定mark名称运行就可以。

**解决:**在测试用例方法上加@pytest.mark.标记名

执行:
- s参数:输出所有测试用的print信息
- -m: 执行自定义标记相关用例,如pytest -s -m 自定义标记名称

方法一:在conftest.py中配置自定义标记
conftest.py

# import pytest
def pytest_configure(config):marker_list = ["search", "login"]  # 标签名集合for markers in marker_list:config.addinivalue_line("markers", markers)

方法二:通过pytest.ini配置自定义标记

[pytest]
markers =login: 登录测试用例search: 搜索用例

测试用例代码执行相同。
test_main.py

import pytest@pytest.mark.login
def test_login():print("登录用例")@pytest.mark.search
def test_search1():print("搜索用例1")@pytest.mark.search
def test_search2():print("搜索用例2")if __name__ == '__main__':pytest.main()

运行结果:

多线程并行与分布式执行

**场景:**测试用例1000条,一个用例执行1分钟,一个测试人员执行需要1000分钟。通过我们会用人力成本换取时间成本,加几个人一起执行,时间就会缩短。如果10个人一起执行只需要100分钟,这就是一种并行测试,分布式场景。

解决: pytest分布式执行插件pytest-xdist,多个CPU或主机执行。前提条件:用例之间都是独立的,没有先后顺序,随机都能执行,可重复运行不影响其他用例。

安装:
- pip install pytest-xdist
- 多个CPU并行执行用例,直接加-n 3是并行数量 pytest -n 3
- 在多个终端下一起执行

pytest-html生成报告

安装:pip install pytest-html
生成html报告:pytest -v -s --html=report.html --self-contained-html

pytest测试框架相关推荐

  1. Pytest测试框架(二):pytest 的setup/teardown方法

    系列文章目录 Pytest测试框架(一):pytest安装及用例执行 Pytest测试框架(二):pytest 的setup/teardown方法 Pytest测试框架(三):pytest fixtu ...

  2. Python编程必不可少的pytest测试框架

    进行编程测试重要的是为了更高效的完成功能的实现. pytest是基于unittest实现的第三方测试框架,比 unittest 更加的简洁.高效,并且可以完美兼容 unittest 的测试代码,无需对 ...

  3. Pytest 测试框架——数据驱动

    引言 前面已经和大家介绍过 Unittest 测试框架的数据驱动框架 DDT,以及其实现原理.今天和大家分享的是 Pytest 测试框架的数据驱动,Pytest 测试框架的数据驱动是由 pytest ...

  4. Pytest测试框架(五):pytest + allure生成测试报告

    系列文章目录 Pytest测试框架(一):pytest安装及用例执行 Pytest测试框架(二):pytest 的setup/teardown方法 Pytest测试框架(三):pytest fixtu ...

  5. pytest测试框架_聊聊 Python 的单元测试框架(三):最火的 pytest

    本文首发于 HelloGitHub 公众号,并发表于 Prodesire 博客. 一.介绍 本篇文章是<聊聊 Python 的单元测试框架>的第三篇,前两篇分别介绍了标准库 unittes ...

  6. pytest测试框架4-插件与hook函数

    一.简介 pytest的自带功能很强大,通过添加插件可以扩展功能,pytest的代码结构适合定制和扩展插件, 可以借助hook函数来实现. 把fixture函数或者hook函数添加到conftest文 ...

  7. Pytest测试框架的基本使用和allure测试报告

    一.测试用例的识别与运行 目录识别 通过pytest.ini配置文件配置 如果未指定任何参数,则收集从testpaths(如已配置)或当前目录开始.另外,命令行参数可以在目录.文件名或节点ID的任何组 ...

  8. 自动化测试 —— Pytest测试框架

    01 | 简介 Pytest是一个非常成熟的全功能的Python测试框架,主要有以下特点: 简单灵活,容易上手,文档丰富 支持参数化,可以细粒度地控制测试用例 支持简单的单元测试与复杂的功能测试,还可 ...

  9. Pytest系列——allure(原理)之allure工具与Pytest测试框架集成

    官方介绍 1.Allure Framework是一种灵活的轻量级多语言测试报告工具,不仅可以以简洁的Web报告形式非常简洁地显示已测试的内容,也允许参与开发过程的每个人从日常测试中提取最大程度的有用信 ...

  10. pytest测试框架——allure报告

    文章目录 一.allure的介绍 二.allure的运行方式 三.allure报告的生成 方式一.在线报告.会直接打开默认浏览器展示当前报告 方式二.静态资源文件报告(带index.html.css. ...

最新文章

  1. R语言nchar函数统计字符串中字符个数实战
  2. oracle rownum分页 出现重复数据
  3. 这款 IDE 插件再次升级,让「小程序云」的开发部署提速 8 倍
  4. jmeter定时器的使用_jmeter压测学习30定时器之固定定时器(sleep等待时间)
  5. (三十)java多线程一
  6. windows 服务实例
  7. 转帖一篇关于DELPHI调试的文章-AQTime
  8. delphi构造析构调用顺序
  9. postgresql: the application server could not be contacted --2020-11-17
  10. 如何理解图片RGB通道在python(numpy)中的数据构成
  11. Chromium DevTools-frontend 源码构建流程-Windows系统
  12. php监听input,js实时监听input中值变化
  13. win10离线安装framework3.5以及dism找不到源文件解决方法(已测试有效)
  14. vue项目打包部署注意点 + 宝塔面板几步部署项目
  15. dsp31段最佳调音图_31段均衡器调整方法详解,音响调音师必备!
  16. Springboot集成rabbitmq实现延时队列
  17. HDU_01背包系列
  18. 视频营销—网络营销的一种有效形式
  19. 杭州人才补助领取遇到的问题
  20. 校友录(alumni record)项目部署的最详细说明

热门文章

  1. win7 隐藏任务栏操作中心图标
  2. 【NWPU2018 练着玩】入门班day1 枚举贪心[Cloned] F - Claris and XOR (HDU-5661 Claris and XOR )
  3. start-stop-daemon 安装及使用
  4. 2021-07-29 打印机不出现PDF打印
  5. H5界面调用原生,实现拍照、选择图库和文件功能
  6. 特效动画的播放机制,你真的了解吗?
  7. 喜马拉雅XM文件转MP3格式教程
  8. python bytearray拼接_python-4-bytes和bytearray
  9. B.FRIENDit壁虎忍者G2游戏鼠标 台式笔记本外接电竞LOL背光游戏鼠标
  10. vue加载three模型成功,但显示黑屏?