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}")
posted @   bjyxxc  阅读(87)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
点击右上角即可分享
微信分享提示