pytest+fastapi 简易的单元测试使用指引
[pytest]单元测试使用指引
单元测试框架主要功能:发现测试用例=》执行测试用例=》判断测试用例=》生产测试报告
1.测试用例格式
命名规则:
1.模块文件必须以test_开头或者_test结尾
2.类名必须以Test开头
3.方法名必须以test开头
test_demo.py
class TestDemo:
def test_demo1(self):
print('测试用例1')
def test_demo2(self):
print('测试用例2')
2.全局配置文件 pytest.ini
[pytest]
/*测试用例的路径,可自己配置,
../pytestproject为上一层的pytestproject文件夹
./testcase为pytest.ini当前目录下的同级文件夹
改变用例的查找路径规则,当前目录的test文件夹*/
testpaths =./test
/*模块名的规则,配置测试搜索的模块文件名称*/
python_files = test*.py
/*类名的规则,配置测试搜索的测试类名*/
python_classes = Test*
/*方法名的规则,配置测试搜索的测试函数名*/
python_functions = test
/*addopts:配置命令行参数,用空格进行分隔
可执行标记为mark的对应用例,用or表示标记为demo或者smoke的用例都会执行*/
addopts = -vs --alluredir=./results/json --clean-alluredir -m "demo or smoke"
/*注册 mark 标记*/
markers =
demo : marks tests as demo
smoke: 冒烟用例
user_mansge:用户管理用例
minversion = 5.0
test_markers_demo.py
import pytest
@pytest.mark.smoke
def test_example_smoke():
assert 1+1 ==2
@pytest.mark.user_manage
def test_example_user_manage():
assert 2*2 == 4
命令行执行
# pytest -m smoke 执行单个
pytets -m "smoke and user_manage" 执行多个
3.执行pytest方式
使用命令行执行
# 直接在命令行执行,如果存在pytest.ini会根据文件内容进行执行,如果没有则默认格式执行
# -vs: -v输出详细信息 -s输出调试信息
pytest -vs
# -n: 多线程运行(前提安装插件:pip install pytest-xdist)
pytest -vs -n=2
# --reruns num: 失败重跑(前提安装插件:pip install pytest-rerunfailres)
pytest -vs --reruns=2
# -x: 出现一个用例失败则停止测试
pytest -vs -x
# --maxfail: 出现几个失败才终止
pytest -vs --maxfail=2
# --html: 生成html的测试报告,后面 需要跟上所创建的文件位置及文件名称(前提安装插件:pip install pytest-html)
pytest -vs --html ./reports/result.html
# -k: 运行测试用例名称中包含某个字符串的测试用例,我们可以采用or表示或者,采用and表示都
pytest -vs -k "qiuluo"
pytest -vs -k "qiuluo or weiliang"
pytest -vs -k "qiuluo and weiliang"
# -m:冒烟用例执行,后面需要跟一个冒烟名称,执行user_manage这个分组
pytest -vs -m user_manage
使用pytest.main方法执行
import pytest
if __name__ == '__main__':
# 执行某个模块下某个类下的测试用例并生成简易的测试报告
# pytest.mian(['-vs', '--html=report.html', 'test_xxx.py::TestPgSQL::test_exec_pg_sql'])
# 执行某个模块下某个类下的测试用例
# pytest.mian(['-vs', 'test_xxx.py::TestPgSQL::test_exec_pg_sql'])
# 执行某个模块下的某个类中所有测试用例
# pytest.mian(['-vs', 'test_xxx.py::TestPgSQL'])
# 执行某个模块下所有类的测试用例
# pytest.mian(['-vs', 'test_xxx.py'])
4.测试结果
.代表一个测试用例通过,…代表两个测试用例通过,以此类推;
s,即Skip,代表用例跳过执行;
F,即Failure,一般是断言发生错误;
E,即Error,一般是用例执行过程中报错。
5.断言方法
assert xx:判断 xx 为真
assert not xx:判断 xx 不为真
assert a in b:判断 b 包含 a
assert a == b:判断 a 等于 b
assert a !=b:判断 a 不等于 b
6.@pytest相关方法使用(相关)
@pytest.fixture(scope=None, autouse=False, params=None, ids=None, name=None)
scope:作用范围,参数有三种(function函数、class类、package包、session会话)=》作用域
function:在执行函数时前后置的条件。通常用yield进行前后置划分,yield前是前置,yield后是后置。也可以通过return返回,但后置条件没法执行。
class:在执行类前后置条件。
package:在文件夹执行前后的前后置条件。
session:最大、全局、会话前后置条件。
autouse:Flase,默认情况下不会自动启动。为True则自动启动,则所有方法在执行时都会自动执行该前后置,为Flase则需要手动参数传入。
params:实现参数化配置。
class TestDemo:
def read_yaml(self):
return ["张三","李四","王五"]
@pytest.fixture(scope='function', autouse=False, params=read_yaml(None))
def exec_database_sql(self, request):
yield request.param
ids:和params一起使用,作用对参数起别名,就是修改了console控制台展示的数据。
name:对fixture起别名。
test_fixture_demo.py
同步fixture:
class TestRedis:
@pytest.fixture(scope='function', autouse=True)
def exec_redis_detect(self):
redis_host = '127.0.0.1'
redis_port = 6379
redis_pwd = ''
pool = redis.ConnectionPool(host=redis_host, port=redis_port, password=redis_pwd, decode_responses=True)
r = redis.Redis(connection_poll=pool)
print("==redis建立连接==")
yield r
print("==redis断开连接==")
@pytest.mark.asyncio
async def test_exec_redis_detect(self, exec_redis_detect)
print(type(exec_redis_detect), exec_redis_detect)
all_items = exec_redis_detect.hgetall("xxx")
print(all_items)
assert len(all_items) >= 1
异步fixture:
class PgsqlDAO(DAO):
def __init__(self, db_url):
super(PgsqlDAO, self).__init__(db_url)
class TestPgSQLDemo:
@pytest.fixture(scope='fixture', autouse=True)
async def exec_pg_sql(self):
dao = PgsqlDAO(local_pg_url)
await dao.connect
print("pgsql建立连接")
yield dao
await dao.disconnect()
print("pgsql断开连接")
@pytest.mark.asyncio
async def test_exec_pg_sql(self, exec_pg_sql):
select_sql = "select * from test_table"
print(type(exec_pg_sql), exec_pg_sql)
# 异步生成器
async for pg_conn in exec_pg_sql:
data_list = await pg_conn.fetch_all(sql=select_sql)
for row in data_list:
print("name", row.name)
assert len(data_list) >= 1
mian_demo.py
@pytets.mian()
启动项目,用命令行参数指定模式和用例执行
-s:显示程序中的打印和日志输出
-v:丰富信息模式,输出更详细的用例执行信息
-q:安静模式,不输出环境信息
-x:出现一条测试用例则失败退出测试,调试阶段非常有用
-k:可以使用and、农田、or等逻辑运算符,区分匹配范围(文件名、类名、函数名)
xfail_demo.py
与pytest.skip有点相似。将该用例标记成失败,则该用例后续代码中不会执行。
7.@pytest.mark相关方法使用(部分)
@pytest.mark.asyncio
用来测试异步代码的测试用例。可执行单个测试用例或多个。
@pytest.mark.parametrize("param1, param2, ..., expected", [(param1, param2, ..., expected)])
参数化测试用例, 就是为测试函数提供多组输入参数和预期输出。
@pytest.mark.usefixtures('fixture_func1', 'fixture_func2')
是pytest调用fixture的方法之一,与直接传入fixture不同的是,它无法获取到被fixture装饰的函数的返回值。使用场景在测试函数需要多个fixtrue前后置条件工作时使用。
@pyets.fixture()
def func1():
pass
@pytest.fixture()
def func2():
pass
@pytest.mark.usefixture('func1', 'func2')
async def test_func():
pass
@pytest.mark.usefixture('func2')
@pytest.mark.usefixture('func1')
async def test_func2():
pass
(叠加:自下到上的执行)
@pytest.mark.skip(reson='')
无理由无条件跳过被装饰的测试用例。
@pytest.mark.skipif
有条件为true时跳过被装饰的测试用例。
@pytest.mark.filterwarnings
捕获并过滤,禁用,自定义警告信息
@pytest.mark.xfail
期望测试用例是失败的。但不会影响测试用例的执行,如果测试用例执行失败结果是xfailed(不会有额外显示报错信息),如果成功结果是xpassed。
8.添加logger日志信息
下载
pip install loguru
基本使用
from loguru import logger
logger.info(f"获取结果:{data}")
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?