FastAPI测试策略:参数解析单元测试

news/2025/3/18 19:22:13/文章来源:https://www.cnblogs.com/Amd794/p/18779592

image

image

扫描二维码关注或者微信搜一搜:编程智域 前端至全栈交流与成长

探索数千个预构建的 AI 应用,开启你的下一个伟大创意


第一章:核心测试方法论

1.1 三层测试体系架构

# 第一层:模型级测试
def test_user_model_validation():with pytest.raises(ValidationError):User(age=-5)# 第二层:依赖项测试
def test_auth_dependency():assert auth_dependency(valid_token).status == "active"# 第三层:端点集成测试
def test_user_endpoint():response = client.get("/users/1")assert response.json()["id"] == 1

1.2 参数化测试模式

import pytest@pytest.mark.parametrize("input,expected", [("admin", 200),("guest", 403),("invalid", 401)
])
def test_role_based_access(input, expected):response = client.get("/admin",headers={"X-Role": input})assert response.status_code == expected

第二章:请求模拟技术

2.1 多协议请求构造

from fastapi.testclient import TestClientdef test_multi_part_form():response = TestClient(app).post("/upload",files={"file": ("test.txt", b"content")},data={"name": "test"})assert response.status_code == 201def test_graphql_query():response = client.post("/graphql",json={"query": "query { user(id:1) { name } }"})assert "errors" not in response.json()

2.2 动态Header注入

class AuthTestClient(TestClient):def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)self.token = generate_test_token()def get(self, url, **kwargs):headers = kwargs.setdefault("headers", {})headers.setdefault("Authorization", f"Bearer {self.token}")return super().get(url, **kwargs)test_client = AuthTestClient(app)

第三章:Pydantic深度测试

3.1 自定义验证器测试

def test_custom_validator():with pytest.raises(ValidationError) as excinfo:Product(stock=-10)assert "库存不能为负" in str(excinfo.value)def test_regex_validation():valid = {"email": "test@example.com"}invalid = {"email": "invalid-email"}assert EmailRequest(**valid)with pytest.raises(ValidationError):EmailRequest(**invalid)

3.2 模型继承测试

class BaseUserTest:@pytest.fixturedef model_class(self):return BaseUserclass TestAdminUser(BaseUserTest):@pytest.fixturedef model_class(self):return AdminUserdef test_admin_privilege(self, model_class):user = model_class(role="super_admin")assert user.has_privilege("all")

第四章:测试覆盖率优化

4.1 边界条件覆盖策略

# 使用hypothesis生成测试数据
from hypothesis import given, strategies as st@given(st.integers(min_value=0, max_value=150))
def test_age_validation(age):assert 0 <= User(age=age).age <= 120@given(st.text(min_size=1, max_size=50))
def test_username_validation(name):if not name.isalnum():with pytest.raises(ValidationError):User(username=name)else:assert User(username=name)

4.2 依赖覆盖测试

def test_external_service_override():mock_service = MockExternalService()app.dependency_overrides[get_external_service] = lambda: mock_serviceresponse = client.get("/data")assert response.json() == mock_service.expected_dataapp.dependency_overrides = {}

第五章:异常处理测试

5.1 错误传播验证

def test_error_chain():with pytest.raises(HTTPException) as excinfo:client.get("/error-path")exc = excinfo.valueassert exc.status_code == 500assert "原始错误" in exc.detaildef test_validation_error_format():response = client.post("/users", json={"age": "invalid"})assert response.status_code == 422assert response.json()["detail"][0]["type"] == "type_error.integer"

5.2 压力测试场景

def test_concurrent_requests():with ThreadPoolExecutor() as executor:futures = [executor.submit(client.get,f"/items/{i}") for i in range(1000)]results = [f.result().status_code for f in futures]assert all(code == 200 for code in results)

课后Quiz

Q1:如何测试需要认证的端点?
A) 直接访问无需处理
B) 使用自定义TestClient注入Header
C) 关闭服务端认证

Q2:参数化测试的主要作用是?

  1. 减少测试代码量
  2. 覆盖多种边界条件
  3. 提高单个测试速度

Q3:如何验证自定义验证器?


错误解决方案速查表

测试错误类型 解决方案
依赖项初始化失败 检查测试依赖覆盖是否正确定义
验证错误未触发 确认测试数据包含非法边界值
异步断言失败 使用pytest-asyncio管理异步测试
临时文件残留 使用tmp_path夹具自动清理

扩展工具推荐

  1. pytest-cov - 测试覆盖率分析
  2. Hypothesis - 基于属性的测试框架
  3. responses - 外部请求模拟库
  4. factory_boy - 测试数据工厂

测试箴言:优秀的测试体系应遵循测试金字塔原则,单元测试占比不低于70%。建议采用Given-When-Then模式编写测试用例,保持单个测试的原子性,使用突变测试检测测试有效性,并定期进行测试代码重构。

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:

往期文章归档:

  • FastAPI性能优化指南:参数解析与惰性加载 | cmdragon's Blog
  • FastAPI依赖注入:参数共享与逻辑复用 | cmdragon's Blog
  • FastAPI安全防护指南:构建坚不可摧的参数处理体系 | cmdragon's Blog
  • FastAPI复杂查询终极指南:告别if-else的现代化过滤架构 | cmdragon's Blog
  • FastAPI 核心机制:分页参数的实现与最佳实践 | cmdragon's Blog
  • FastAPI 错误处理与自定义错误消息完全指南:构建健壮的 API 应用 🛠️ | cmdragon's Blog
  • FastAPI 自定义参数验证器完全指南:从基础到高级实战 | cmdragon's Blog
  • FastAPI 参数别名与自动文档生成完全指南:从基础到高级实战 🚀 | cmdragon's Blog
  • FastAPI Cookie 和 Header 参数完全指南:从基础到高级实战 🚀 | cmdragon's Blog
  • FastAPI 表单参数与文件上传完全指南:从基础到高级实战 🚀 | cmdragon's Blog
  • FastAPI 请求体参数与 Pydantic 模型完全指南:从基础到嵌套模型实战 🚀 | cmdragon's Blog
  • FastAPI 查询参数完全指南:从基础到高级用法 🚀 | cmdragon's Blog
  • FastAPI 路径参数完全指南:从基础到高级校验实战 🚀 | cmdragon's Blog
  • FastAPI路由专家课:微服务架构下的路由艺术与工程实践 🌐 | cmdragon's Blog
  • FastAPI路由与请求处理进阶指南:解锁企业级API开发黑科技 🔥 | cmdragon's Blog
  • FastAPI路由与请求处理全解:手把手打造用户管理系统 🔌 | cmdragon's Blog
  • FastAPI极速入门:15分钟搭建你的首个智能API(附自动文档生成)🚀 | cmdragon's Blog
  • HTTP协议与RESTful API实战手册(终章):构建企业级API的九大秘籍 🔐 | cmdragon's Blog
  • HTTP协议与RESTful API实战手册(二):用披萨店故事说透API设计奥秘 🍕 | cmdragon's Blog
  • 从零构建你的第一个RESTful API:HTTP协议与API设计超图解指南 🌐 | cmdragon's Blog
  • Python异步编程进阶指南:破解高并发系统的七重封印 | cmdragon's Blog
  • Python异步编程终极指南:用协程与事件循环重构你的高并发系统 | cmdragon's Blog
  • Python类型提示完全指南:用类型安全重构你的代码,提升10倍开发效率 | cmdragon's Blog
  • 三大平台云数据库生态服务对决 | cmdragon's Blog
  • 分布式数据库解析 | cmdragon's Blog
  • 深入解析NoSQL数据库:从文档存储到图数据库的全场景实践 | cmdragon's Blog
  • 数据库审计与智能监控:从日志分析到异常检测 | cmdragon's Blog
  • 数据库加密全解析:从传输到存储的安全实践 | cmdragon's Blog
  • 数据库安全实战:访问控制与行级权限管理 | cmdragon's Blog
  • 数据库扩展之道:分区、分片与大表优化实战 | cmdragon's Blog
  • 查询优化:提升数据库性能的实用技巧 | cmdragon's Blog
  • 性能优化与调优:全面解析数据库索引 | cmdragon's Blog
  • 存储过程与触发器:提高数据库性能与安全性的利器 | cmdragon's Blog
  • 数据操作与事务:确保数据一致性的关键 | cmdragon's Blog
  • 深入掌握 SQL 深度应用:复杂查询的艺术与技巧 | cmdragon's Blog

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/901066.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MSTP协议

一、MSTP(多生成树协议)简介 1.1 MSTP(多生成树协议)使用场景MSTP(Multiple Spanning Tree Protocol,IEEE 802.1s), 基于 RSTP 的多实例扩展协议,通过划分多个生成树实例(MSTI)实现 VLAN 与生成树的灵活映射,在保留 RSTP 快速收敛特性的基础上,支持 多拓扑负载均衡…

Eth-Trunk协议

一、Eth-Trunk(链路聚合协议)使用场景 1.1 Eth-Trunk(链路聚合协议)简介​ 原名叫链路聚合组(Link Aggregation Group),通过将多个物理接口捆绑为一个逻辑接口,可以在不进行硬件升级的条件下,达到增加链路带宽的目的。1.2 Eth-Trunk(链路聚合协议)实现目的增加带宽链…

PPP协议

一、PPP(点对点协议)简介 1.1 PPP使用场景​ 我们家庭中使用最多的宽带接入方式就是PPPoE(PPP over Ethernet)。这是一种PPP利用以太网(Ethernet)资源,在以太网上运行PPP来对用户进行接入认证的技术,PPP负责在用户端和运营商的接入服务器之间建立通信链路。二、PPP(点…

以太帧格式

一、以太帧使用场景 1.1 Ethernet Ⅱ以太帧简介​ Ethernet II(又称 DIX 2.0)是最广泛使用的以太网帧格式,由DEC、Intel和Xerox在1982年标准化,是TCP/IP网络中最常见的链路层协议。1.2 Novell Netware 802.3 Raw以太帧简介​ 这是 1983 年 Novell 发布其划时代的 Netware/8…

单臂路由

一、单臂路由简介 1.1 单臂路由使用场景​ 单臂路由(Router-on-a-Stick)是一种通过路由器单个物理接口的多个逻辑子接口实现不同VLAN间通信的解决方案,其核心是利用802.1Q协议在交换机的Trunk链路传输多VLAN流量,路由器通过子接口为每个VLAN分配网关并完成跨网段路由。该方…

Windows 提权-服务_弱服务权限

本文通过 Google 翻译 Weak Service Permissions – Windows Privilege Escalation 这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校正及个别注释补充。导航0 前言 1 搜寻非标准服务1.1 cmd 1.2 powershell2 搜寻服务的弱权限2.1 枚举服务的弱权限:手动 2.2 …

前端html+css+js

之前只知道html和css,不知道可以用js设置事件监听,一些输入判断条件就不知道怎么写,上了web课程后有所了解 这是此次作业代码是ai生成的,不过可以凭自己大致看懂,加上ai的解释和课堂ppt有所收获点击查看代码 <!DOCTYPE html> <html lang="zh"> <…

Git分支管理与代码合并实践:保持特性分支与主分支同步

场景说明 在团队协作开发中,开发者经常需要在特性分支(如 dev_feature_xxx)上实现新功能,同时需要定期同步主分支(如 develop)的最新代码,避免最终合并时产生严重冲突。本文将通过一个实际案例,演示如何安全地将主分支更新合并到特性分支,并完成代码推送与合并请求。完…

dify工作流

一、简介 官方地址:https://docs.dify.ai/zh-hans/guides/workflow工作流通过将复杂的任务分解成较小的步骤(节点)降低系统复杂度,减少了对提示词技术和模型推理能力的依赖,提高了 LLM 应用面向复杂任务的性能,提升了系统的可解释性、稳定性和容错性。 Dify 工作流分为两…

wps实现多选下拉框3种方案

一、js宏listbox控件方案 优点: 1.wps默认宏环境,无需安装VBA环境 2.下拉框位置定位准确 缺点: 1.下拉框数据无法代码初始化,只能使用区域设置 2.一次只能选一个,多次选择实现多选 配置: 代码:function ListBox1_Click() {var cellValue = new String(ActiveCell.Valu…

Nginx 离线安装与介绍

一、安装 1.1 离线安装准备源代码包 #从项目的官方网站或代码仓库(如 GitHub)下载源代码 wget https://nginx.org/download/nginx-1.24.0.tar.gz #下载 tar -xzvf nginx-1.24.0.tar.gz #解压 cd nginx-1.24.0安装编译工具和依赖项 #正则表达式库(pcre-devel)、 数…

安装U8 IEWebControls 提示“The specified path http://localhost/webctrl client is unavailable.

安装U8 插件 IEWebControls 提示“The specified path "http://localhost/webctrl client is unavailable. The InternetInformation Server might not be running or the path exists and is redirected to anothelmachine. Please check the status of this virtual di…