一、单元测试对开发者的重要性
- 1. 确保代码质量。通过编写单元测试,可以确保代码遵循设计要求和业务逻辑,功能正确。这可以大大减少 bug 的产生,保证代码质量。
- 2. 简化集成测试。有了可靠的单元测试作为基础,集成测试的难度和范围就能大大减小。集成测试可以更 focused 地检验模块之间的集成与接口。
- 3. 便于重构。有了单元测试,开发者可以随时重构代码而不用担心改动后的代码出现问题。重构后的代码仍然可以通过单元测试,这可以给开发者很大信心。
- 4. 文档化。单元测试可以视为代码的一种文档,阅读单元测试可以了解代码要实现的功能和业务逻辑。这在新人上手项目或老代码维护时 especially 有用。
- 5. 可持续集成的基石。可持续集成的第一步就是运行所有的单元测试。只有单元测试通过,代码才能被合并进入主线。这可以最大限度地确保主线代码的质量。
- 6. 所以总的来说,编写单元测试可以让开发更高效、代码更健壮。它是构建高质量代码和可持续集成的基础,是现代软件工程中不可或缺的一部分。开发者要养成为任何代码编写单元测试的好习惯。
二、简介
python-fro-pytest是依赖于python3+以及pytest模块,用于构建api接口测试用例数据模板的生成与读取(保存在excel文件中目前仅支持xls格式),并提供flask与sanic框架的通用测试用例方法的自动生成。
三、安装
pip install python-for-pytest
四、使用
- 1. 在项目工程根目录下创建test包,您的测试用例文件都可以写在其中
# 目录结构大概如下
your_project_dir
|-- app
|-- test
|--__init__.py
- 2. 本工具提供关于flask和sanic框架通用的单元测试样例脚本,可自动生成测试样例脚本供参考,代码如下
# 在test包下的__init__.py文件中调用如下代码,会生成一个参考样例脚本
from pathlib import Path
from python_for_pytest import init_pytest_for_flask
# from python_for_pytest import init_pytest_for_sanic
base_path = Path(__file__).resolve().parent
init_pytest_for_flask(base_path,"custom_script_name.py")
- 3. 根据测试样例脚本的提示,准备您预测试的接口json报文样例,并按要求在报文根节点下添加uri、method、result、message节点,例如下面示例
# 单个接口
api={
"uri": "/test/get", # 接口的访问资源路径
"method": "get", # 接口的请求方法
"result":"0", # 预期结果
"message":"操作成功,符合预期", # 对预期结果的说明
"head": {
"sysCode": "11111",
"appCode": "22222",
"sign": "99999999"
}
}
# 多个接口,将每个接口样例添加到列表中
api = [
{
"uri": "/test/get",
"method": "get",
"result":"0", # 预期结果
"message":"操作成功,符合预期", # 对预期结果的说明
"head": {
"sysCode": "11111"
},
"biz": {
"phoneNumber": "1111111111",
"developPerson": "1232221",
"prod_info": [
{
"prod_nbr": "444444"
}
]
}
},
{
"uri": "/test/post",
"method": "post",
"result":"0", # 预期结果
"message":"操作成功,符合预期", # 对预期结果的说明
"head": {
"reqTime": "2015-01-23 15:32:03",
"sign": "3333"
},
"biz": {
"serialnum": "12",
"prod_info": [
{
"prod_nbr": "1111"
},
{
"prod_nbr": "2222"
}
]
}
}
]
- 4. 报文及测试样例写好后,就可以在terminal下执行如下命令,进行单元测试
cd test
pytest test_xxxx.py
五、测试用例样例
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# author:Sun
# datetime:2023
# flask框架单元测试样例脚本
import json
from pathlib import Path
from urllib import parse
from functools import reduce
import pytest
from python_for_pytest import (init_template, setup_read_main)
_file_name = "mock_data.xls"
_title_type = 1 # 0:报文参数名写在行,1:报文参数名写在列
_base_path = Path(__file__).resolve().parent
# TODO: 0.根据接口报文初始化生成测试数据模板【您需要更改下面request_data变量代表的请求报文】
request_mock_data = {
"uri": "/test",
"method": "post",
"result": "0",
"message": "操作成功,符合预期",
"head": {
"sysCode": "111111",
"appCode": "22222",
"reqTime": "2022-09-19 00:00:00",
},
"biz": {
"phone": "18638720197",
"sale_code": "7240110003400005",
"prod_info": [
{
"prod_nbr": "xxxxxx"
}
]
}
}
init_template(data=request_mock_data, base_path=_base_path, excel_file_name=_file_name, t_type=_title_type)
# TODO:1.读取配置好的测试数据
source_data = setup_read_main(source_path=_base_path, f_name=_file_name, t_type=_title_type)
# [{},{}] 如果每个接口的响应格式一样可以采用下面的方面将每个接口合并在一起测试
demo_data = reduce(lambda x, y: x + y, source_data.values())
# 2. 接口测试,需先使用flask提供的测试客户端进行测试,flask自带测试客户端,直接模拟终端请求
@pytest.fixture
def api_mock_client():
"""
构建业务的测试客户端,从而能调用业务应用的接口
:return:
"""
# TODO : 2.导入业务应用对象
from YourApplication import app
with app.test_client() as client:
yield client
# TODO:3.编写测试样例【本例适用于api接口测试,以统一响应格式的code进行判断是否符合预期】
@pytest.mark.parametrize("mock_data", demo_data)
def test_api(mock_data: dict, api_mock_client):
http_headers = {"User-Agent": "TestApp"}
http_method = mock_data.pop("method")
request_uri = mock_data.pop("uri")
test_result = mock_data.pop("result")
test_message = mock_data.pop("message")
request_data = mock_data
print(f"请求{http_method}|{request_uri}报文:{request_data}")
if http_method.upper() == "POST":
response = api_mock_client.post(request_uri, data=json.dumps(request_data), headers=http_headers)
else:
request_data = parse.urlencode(request_data)
request_uri = f"{request_uri.rstrip('/')}?{request_data}" if request_uri.endswith(
"/") else f"{request_uri}?{request_data}"
response = api_mock_client.get(request_uri, headers=http_headers)
print(f"原始响应为:{response.data}")
# TODO :4.如果不同接口响应结构不同,请自行修改下面的代码
response_data = response.json
assert int(response_data["code"]) == int(test_result), test_message
六、备注说明
本工具初始化会自动生成测试用例数据源excel文件,pytest.ini配置文件,单元测试脚本模板文件
保存测试数据到excel表 表格式说明如下:
- 1. 每个sheet【标签页】代表一个接口
- 2. 每列表示请求报文中的字段,如果涉及到层级关系需要以点分隔,如biz.dataObject.code,如果是列表将增加数字代表列表index
- 3. 测试数据文件名默认为:mock_data.xls,支持自定义
- 4. 提供的报文必须在json一级中增加字段:uri【接口资源路径】,method【接口请求方法】,result【预期结果】,message【对预期结果的说明】
- 5. 如果一次提交多个接口,以列表包裹字典,每个字典代表一个接口
- 6. 支持自定字段是存在每列,或每行
- 7. 用户可以编辑excel文件,为每个excel添加多组数据,测试不同的预期结果