Pytest框架基础
一、pytest基础使用
1.安装和介绍
1.概念
pytest 是 python 的一种单元测试框架,同自带的 Unittest 测试框架类似,相比于 Unittest 框架使用起 来更简洁,效率更高
2.官网地址
https://docs.pytest.org/en/latest/
3.中文文档地址
https://www.osgeo.cn/pytest/
4.特点
- 易上手,入门简单,文档丰富,文档与现实中有很多实例可供参考
- 支持简单的单元测试和功能测试
- 具有很多第三方插件,且多数可以自定义扩展
- 支持参数化
- 可以很方便的与持续集成工具进行集成
- 支持运行 由 Unittest,Nose编写的测试脚本case
- 支持重复执行失败的case
- 支持case跳过,测试结果标记等功能
5.安装与使用
1.安装
通过pip命令安装指定版本
pip install pytest==x.x.x
2.使用
import pytest
6.规则与规范
1.规则
pytest是python的第三方测试框架 ,是基于unittest的扩展框架 ,比unittest更简洁 ,更高效。使用 pytest编写用例 ,必须遵守以下规则
- 测试文件名必须以“test**”开头或者"**test"结尾。(如:test_ab.py)
- 测试类命名以“Test”开头。用例识别: 包含所有test_*的方法(测试类不能带有—init—方法)
- 测试方法必须以“test**”**开头。
2.规范
- 模块名:一般全小写:多个英文之间用_隔开。_
- 类名:类名一般是首字母大写
- 方法名:一般全小写:多个英文之间用_隔开。
例:
class TestDemo:
def test_01:
pass
def test_02:
pass
def test_03:
pass
2.运行
1.运行方式
1.命令行运行
#命令行运行
pytest -s test_demo01.py
2.主函数运行
import pytest
class Test:
def test_case01(self):
print(1)
def test_case02(self):
print(2)
# 主函数执行
if__name__ == '__main__':
#pytest.mian()
pytest.main(['-s','test_demo01.py'])
3.通过pytest.ini的配置文件运行
[pytest] #用于标记这个文件是pytest的配置文件
addopts = -vs #命令行参数,多个参数之间用空格分隔。 addoptions
testpaths = testcases/ #配置搜索测试用例的范围
python_files = test_*.py #改变默认的文件搜索规则
python_classes = Test* #改变默认的类搜索规则
python_functions = test_* #改变默认的测试用例的搜索规则。
#用例分组
markers =
smoke:冒烟用例
productmanage:商品管理模块
特别提示:此文件中最好不要出现中文, 如果有中文的情况下,比如使用notpad++改成GBK的编码。
用例中加标记:
class TestApi:
@pytest.mark.smoke
def test_01(self):
print("测试1")
@pytest.mark.productmanage
def test_02(self):
print("测试2")
执行的时候通过-m参数指定标记:
addopts = ‐vs ‐m smoke
2.常见参数
-v:输出更加详细的信息。比如文件和用例名称等。
-s:输出调试信息。打印信息等。
–reruns 数字:失败重跑
-x:出现1个失败就停止测试
–maxfail=2 出现N个失败就终止测试
–html=report.html 生成html的测试报告
-n:多线程
-k:运行测试用例名称中包含指定字符串的用例。
pytest.main(['-vs','-k','111 or 222'])
pytest.main(['-vs','-k','111 and 222'])
3.setup和teardown
1.介绍
pytest 在运行自动化脚本的前后会执行两个特殊的方法,分别是 setup 和 teardown 在执行脚本之前会执行 setup方法,在执行脚本 之后会执行 teardown 方法,我们可以在 setup 中进行获取驱动对象的操作,在teardown 中进行关闭驱动对象的操作。
2.函数级别的方法
运行于测试方法的始末,运行一次测试函数会运行一次 setup 和teardown。
import pytest
class Test:
def setup(self):
print('test--->setup')
def teardown(self):
print('test--->teardown')
def test_case01(self):
print('test--->1')
def test_case02(self):
print('test--->2')
# 主函数执行
if__name__== '__main__':
pytest.main(['-s','test_demo01.py'])
执行结果:
3.类级别方法
运行于测试类的始末,在一个测试内只运行一次 setup_class 和 teardown_class, 不关心测试类内有多少个测试函数
import pytest
class Test:
def setup_class(cls):
print('test--->setupcls')
def teardown_class(cls):
print('test--->teardowncls')
def test_case01(self):
print('test--->1')
def test_case02(self):
print('test--->2')
# 主函数执行
if__name__== '__main__':
pytest.main(['-s','test_demo01.py'])
执行结果:
4.模块级别方法
import pytest
def setup_module():
print("在每个模块之前执行")
def teardown_module():
print("在每个模块之后执行")
4.fixture夹具
1.语法
@pytest.fixture(scope="作用域",params="数据驱动",autouser="自动执行",ids="自定义参数名称",name="别名")
2.作用域
1.function
描述:
-
在每个方法(测试用例)的前后执行一次
@pytest.fixture(scope="function") def execute_sql(): print("执行数据库的验证,查询数据库。") yield print("关闭数据库的连接")
调用:
-
def test_001(self,execute_sql): print("001"+execute_sql)
2.class
描述:
-
在每个类的前后执行一次。
@pytest.fixture(scope="class") def execute_sql(): print("执行数据库的验证,查询数据库。") yield print("关闭数据库的连接")
调用:
-
@pytest.mark.usefixtures("execute_sql") class TestApi2: def test_duo_class(self): print("多个类的情况")
3.module
描述:
-
在每个模块的前后执行一次。
@pytest.fixture(scope="module",autouse=True) def execute_sql(): print("执行数据库的验证,查询数据库。") yield "1" print("关闭数据库的连接")
4.package、sesion
描述:当fixture的级别为package,session时,那么一般和conftest.py文件一起使用。
5.conftest.py
- 名称固定的conftest.py,主要用于单独的存放fixture固件的。
- 级别为package,sesion时,那么可以在多个包甚至多个py文件里面共享前后置。
- 举例:登录。
- 模块:模块的共性。
- 发现conftest.py文件里面的fixture不需要导包可以直接使用。
- conftest。py文件,可以有多个。
- 作用:出现重复日志,初始化一次日志对象。规避日志重复。连接数据库。关闭数据库。
- 注意:多个前置同时存在的优先级。
- conftest.py为函数级别时优先级高于setup/teardown
- conftest.py为class级别时优先级高于setup_class/teardown_class
- conftest.py为session级别时优先级高于setup_module/teardown_module
5.数据驱动
1.应用场景
登录功能都是输入用户名,输入密码,点击登录。但登录的用户名和密码如果想测试多个值是没有办法 用普通的操作 实现的。数据参数化可以帮我实现这样的效果。
2.语法
@pytest.mark.parametrize(argnames, argvalues, indirect=False, ids=None, scope=None)
- argnames 参数名
- argvalues 参数对应值,类型必须为可迭代类型, 一般使用list 一个参数使用方式
- argnames 为字符串类型,根据需求决定何时的参数名
- argvalues 为列表类型,根据需求决定列表元素中的内容
- 在测试脚本中,参数,名字与 argnames 保持一致
- 在测试脚本中正常使用argvalues 列表有多少个内容,这个脚本就会运行几次
3.示例
class Test:
@pytest.mark.parametrize('age',[18,19,23,21])
def test_01(self,age):
print(age)
6.断言
使用python原生assert 断言即可
二、Pytest-常用插件
1.pytest-Html测试报告
1.应用场景
自动化测试脚本最终执行是通过还是不通过,需要通过测试报告进行体现
2.插件安装
-
命令行安装
pip install pytest-html=x.x.x
3.执行命令
pip install pytest-html=2.1.1
4.查看报告
5.报告展示
2.allure-pytest
第一步
1.官网下载allure文件:https://github.com/allure-framework/allure2/releases
2.下载之后解压到非中文的目录
3.把bin路径配置到系统变量path中:E:\allure-2.13.7\bin (注意分号不要是中文的)
第二步
安装allure报告:pip install allure-pytest
验证:allure --version
注意:可能需要重启pycharm。
第三步
1.pytest.ini
文件如下:
[pytest]
addopts = ‐vs ‐‐alluredir=reports/temps ‐‐clean‐alluredir
testpaths = testcases/
python_files = test_*.py
python_classes = Test*
python_functions = test_*
markers =
smoke:冒烟测试
productmanage:商品管理模块
2.all.py
文件如下:
if __name__ == '__main__':
pytest.main()
time.sleep(3)
os.system("allure generate reports/temps ‐o reports/allures ‐‐clean")
3.pytest-ordering执行顺序
1.应用场景
现实生活中,如果想下订单接口,必须先登录,我们可以通过插件的形式来控制函数执行的顺序
2.插件安装
-
命令行安装
pip install pytest-ordering ==x.x.x
3.使用方法
- 标记于被测试函数, @pytest.mark.run(order=x)
- 根据order传入的参数来解决运行顺序
- order值全为正数或全为负数时,运行顺序:值越小,优先级越高
- 正数和负数同时存在:正数优先级高
示例:
import pytest
class Test:
@pytest.mark.run(order=3)
def test_case01(self):
print('test--->001')
@pytest.mark.run(order=2)
def test_case02(self):
print('test--->002')
@pytest.mark.run(order=2)
def test_case03(self):
print('test--->003')
# 主函数执行
if__name__== '__main__':
pytest.main(['-s','test_demo01.py'])
执行结果:
4.pytest-rerunfailures重跑
1.应用场景
由于网络的原因造成自动化脚本报错,我们可以使用失败重试的插件,当失败后尝试再次运行,一般情况最终 成功可以视为成功, 但最好进行进行排查时候是脚本问题。
2.插件安装
-
命令行安装
pip install pytest-rerunfailures==x.x.x
3.使用方法
-
在配置文件中的命令行参数中增加 --reruns n
pytest -s test_demo2.py --reruns 3
示例:
class Test:
def test_a(self):
assert 1,1 # 断言成功
def test_b(self):
print('失败 ')
assert 0,1 # 断言失败
运行结果: