一、Pytest 介绍
1、基于 python 的单元测试框架
主流的接口测试框架有:
- python:pytest 和 unittest
- java:testng 和 junit
pytest 可以和 selenium,requests,appium 实现 web,接口,app 自动化
2、pytest 强大的 插件
- pytest 本身
- pytest-html 生成html报告
- pytest-xdist 多线程
- pytest-ordering 控制用例的执行顺序
- pytest-rerunfailures 失败用例重跑
- pytest-base-url 处理基础路径(测试,开发,预发布环境,生产)
- allure-pytest 生成allure报告
插件自动安装:
1、在项目根目录创建文件:requirements.txt
2、在文件中写入需要安装的插件名
requirements.txt 内容
pytest
pytest-html
pytest-xdist
pytest-ordering
pytest-rerunfailures
pytest-base-url
allure-pytest
3、在项目根目录打开控制台,执行命令
pip install -r requirements.txt
4、执行命令后,等待安装插件
3、pytest 作用
发现并找到测试用例
pytest 默认规则:
模块名必须以test_开头或_test结尾。
测试类必须以Test开头,并且不能有init方法
测试用例方法必须以test开头
按顺序执行测试用例
通过断言判断测试结果
生成测试报告
二、Pytest 运行方式以及参数
1、命令行运行
在项目目录下通过终端输入:
pytest -vs
2、主函数运行
通常在根目录 创建 run.py 文件
通过主函数调用 pytest.main()
import pytest
if __name__ == '__main__':
pytest.main(["-vs"])
3、pytest.ini 配置文件
不管是命令行还是主函数,都会读取 pytest.ini 配置文件来执行
pytest.ini 文件一般放在项目的根目录
pytest.ini 文件的文件名和参数名都是固定的
需要注意编码格式(如果默认的UTF-8报错就改成GBK,GBK报错就改成UTF-8)
文件内容开头必须带:[pytest] 标志
pytest.ini 文件:
[pytest]
# 配置参数: v 输出详细信息 s 表示调试信息
addopts = -vs
# 改变用例的查找规则,可以使用绝对路径,也可以使用相对路径查找文件夹下用例
testpaths = ./testcases
# 改变模块的查找规则,执行指定开头名称的.py文件
python_files = test_*.py
# 改变类的查找规则
python_classes = Test*
# 改变函数的查找规则
python_functions = test_*
# markes 标记 :addopts 参数中加入 -m "smoke" 就会只运行被标记的用例
# 例如 addopts = -vs -m "smoke",这样就只会运行被标记了 smoke 的用例
# addopts 参数中加入 -m "smoke or user" 同时执行两个被标记的用例
# markes = smoke:冒烟测试
# user:用户名
addopts 常用参数:
- -v 详细信息
- -s 调试信息
- -n 多线程 -n=2
- -x 只要有一个用例失败就停止运行
- -k 根据用例的字符串选择运行 -k "regis or login"
- -m 根据标记运行 -m “smoke or usermanager”
- --maxfail 只要有N个用例失败就停止运行。--maxfail=2
- --reruns 失败用例重跑 --reruns=2
- --html 生成HTML测试报告 --html=./reports/report.html
三、Pytest 跳过测试用例
@pytest.mark.skip(condition,reason="")
condition 为跳过条件,reason 为跳过描述
1、无条件
@pytest.mark.skip(reason="直接跳过")
def test_add(self):
print("这是一个测试用例")
2、有条件
@pytest.mark.skipif(number<10,reason="跳过")
def test_add(self):
print("这是一个测试用例")
四、Pytest测试用例的前后置(固件,夹具)
1、pytest 默认前置和后置函数
def setup_method(self):
print("每个用例前的操作")
def teardown_method(self):
print("每个用例后的操作")
def setup_class(self):
print("每个类前的操作")
def teardow_class(self):
print("每个类后的操作")
2、fixture 装饰器
fixture 是装饰器,语法规则如下:
@pytest.fixture(scope="作用域",params="参数化",autouse="自动执行",ids="参数别名",name="装饰器别名")
fixture 参数介绍:
fixture作用域参数:
scope:"function" (作用于函数)," class" (作用于类), "module" (作用于模块), "session" (作用于会话)
@pytest.fixture(scope="function") # 表示作用于每个函数
def login():
print("函数前")
yield # 固定写法,yield 后面的均会在作用域后执行
print("函数后")
代码演示:
--------------------------------------------------------------------------------
import pytest
@pytest.fixture(scope="function", name="guJian", autouse=False)
def autotest():
print("\n autotest => 执行用例前执行固件")
yield
print("\n autotest => 执行用例后执行固件")
class TestApi:
def test_case_1(self, guJian): # 使用时,传入的参数名需要改为固件的别名,如果用固件本名,会报错
print(" test_case_1")
def test_case_2(self):
print(" test_case_2")
传递参数:
params:[] (通过列表分开传参)
@pytest.fixture(scope="function",params=["mysql","redis"]) # 表示作用于每个函数且带有指定参数
# 执行时,参数将被分开执行,实现参数化
def login(request): # 括号内加 request 固定写法
print("函数前")
yield request.params # 通过 request 将参数传出 固定写法
print("函数后")
代码演示:
--------------------------------------------------------------------------------
import pytest
@pytest.fixture(scope="function", autouse=False, params=["鲁迅", "周树人"])
def autotest(request):
print("\n autotest => 执行用例前执行固件")
yield request.param
print("\n autotest => 执行用例后执行固件")
class TestApi:
# 手动使用 fixture 固件,将固件以参数的形式传递给用例
def test_case_1(self, autotest):