pytest测试代码专用

目录

介绍

pytest 是一个功能强大、灵活且易用的 Python 测试框架,用于编写和运行单元测试、集成测试等。它是 Python 社区中最受欢迎的测试工具之一,相比内置的 unittest 模块,pytest 提供了更简洁的语法、更丰富的功能和更好的扩展性。

  • 官网: pytest.org
  • 安装: 通过 pip 安装 pip install pytest。
  • 版本要求: 当前使用的是 pytest-8.3.5(根据你的输出),这是一个较新的版本,支持 Python 3.12。

不需要继承特定的基类(如 unittest.TestCase),只需写普通的 Python 函数。使用 assert 语句即可进行断言,无需复杂的 self.assertEqual 等方法。

  • 不需要继承特定的基类(如 unittest.TestCase),只需写普通的 Python 函数。
  • 使用 assert 语句即可进行断言,无需复杂的 self.assertEqual 等方法。

配置

pytest.ini

[pytest]
testpaths = tests
pythonpath = .

# pytest -v

在tests/test_exampel:


import pytest

def test_example():
    assert 1 == 1

这就是最简单的例子了

运行:

pytest -v

常用的写法

🧩 一、断言能力(assert)

你可以断的不只是 ==,而是任何 Python 表达式:

def test_math():
    assert 1 + 1 == 2
    assert "hello".upper() == "HELLO"
    assert isinstance(3.14, float)
    assert 5 in [1, 2, 3, 4, 5]

🧪 二、参数化测试(parametrize)

import pytest

@pytest.mark.parametrize("a,b,expected", [
    (1, 2, 3),
    (2, 2, 4),
    (3, 5, 8)
])
def test_add(a, b, expected):
    assert a + b == expected

🔧 三、使用 fixture 管理重复逻辑(数据准备/清理)

user_data() 只写一遍,多个测试用,自动注入

@pytest.fixture
def user_data():
    return {"name": "Alice", "age": 30}

def test_user_name(user_data):
    assert user_data["name"] == "Alice"

def test_user_age(user_data):
    assert user_data["age"] == 30

🧰 四、捕捉异常

def divide(a, b):
    return a / b

def test_divide_by_zero():
    with pytest.raises(ZeroDivisionError):
        divide(1, 0)

🕹️ 五、分组测试(class 测试组织)

class TestMath:
    def test_add(self):
        assert 1 + 1 == 2

    def test_mul(self):
        assert 2 * 3 == 6

你可以运行特定类的测试:


pytest tests/test_example.py::TestMath

运行单个方法
pytest tests/test_example.py::TestMath::test_add

🧼 六、运行顺序和 setup/teardown

@pytest.fixture
def setup_and_teardown():
    print("\nsetup")
    yield
    print("teardown")

def test_abc(setup_and_teardown):
    print("running test")
    assert True

🎁 七、使用命令行参数和调试技巧

•	-v:显示详细信息
•	-x:遇到失败就停止
•	-k "关键字":只运行包含关键字的测试
•	--maxfail=2:最多失败两个就停

✅ 总结格式

pytest <文件路径>::<类名>::<方法名>

测试FastAPI 路由

配合 FastAPI 提供的 TestClient(同步测试)或 AsyncClient(异步测试),你可以轻松写出像这样测试 API 的代码:

同步测试

@app.get("/ping")
def ping():
    return {"msg": "pong"}

测试代码:

from fastapi.testclient import TestClient
from routers.sse_router import app

client = TestClient(app)

def test_ping():
    response = client.get("/ping")
    assert response.status_code == 200
    assert response.json() == {"msg": "pong"}

异步测试

使用异步插件:

pip install pytest-asyncio

在pytest.ini添加:

# pytest.ini
[pytest]
asyncio_mode = auto

还需要:

pip install "httpx[http2]==0.27.0"

🔍 为什么需要 [http2]?

AsyncClient(app=...) 这个功能依赖了 h11, h2, anyio, httpcore, asgiref  ASGI 支持组件

httpx  extra 安装项 [http2] 会自动把它们都装上
问题 原因 解决方式
502 Bad Gateway httpx.app=app 方式不再可靠 ✅ 改用 transport=ASGITransport(app=…)
DeprecationWarning app= 参数已弃用 ✅ 同上
路由未注册/未启动 startup 未被触发 ✅ 使用 ASGITransport 能模拟完整生命周期

测试代码:

@app.get("/hello")
async def hello():
    return {"message": "Hello async!"}

测试:

@pytest.mark.asyncio
async def test_hello():
    # ✅ 推荐使用 transport 显式传入 app,避免 DeprecationWarning & 502 错误
    # 告诉 httpx:“别走网络了,直接通过 ASGI 协议,调用 app 的处理逻辑。”

    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as ac:
        response = await ac.get("/hello")
        assert response.status_code == 200
        assert response.json() == {"message": "Hello async!"}

ASGITransport 是 httpx 专门用于测试 FastAPI(ASGI app)的一种机制,模拟 HTTP 请求过程而不需要真正启动一个 HTTP 服务器。

🔹 1. FastAPI 是 ASGI 应用

FastAPI 完全基于 ASGI(Asynchronous Server Gateway Interface) 构建,不是 WSGI。

你平时运行 FastAPI 都是通过 uvicorn(ASGI server) 启动的。

🔹 2. 测试时你并不想真的启动一个服务器!

我们写测试时,不希望真的启动 uvicorn 开一个端口来跑接口。

而是希望:

• 直接在内存中发请求给 app

• 不用开端口、开线程、搞网络

这就需要一个“模拟器”,来让 AsyncClient 通过 app 发请求,而不是通过 http。

✅ 所以为什么要用 ASGITransport?

原因 说明
✅ 避免真的启动 HTTP 服务(更快) 测试运行速度更快、无需网络
✅ 支持 FastAPI 全生命周期(startup/shutdown) 避免测试中出现未注册路由、连接池等问题
✅ 替代弃用的 AsyncClient(app=app) 官方推荐方式
✅ 支持异步测试 (async def) 与 pytest-asyncio 完美结合

🔍 异步 vs WSGI vs ASGI 的区别总结

名称 类型 说明
WSGI 同步 Django/Flask(旧接口标准)
ASGI 异步 FastAPI/Starlette(新接口标准)
Uvicorn ASGI Server 启动 FastAPI 的服务器
ASGITransport 模拟传输层 专门用于测试 ASGI 应用,无需真正启动服务
用法 示例
测试 POST 请求 client.post(“/login”, json={“user”: “xx”})
添加 Header / token client.get(“/me”, headers={“Authorization”: “Bearer xxx”})
发送 query 参数 client.get(“/items”, params={“page”: 1})
上传文件 client.post(“/upload”, files={“file”: (“name.txt”, b”content”)})
使用 fixture 提供 token 配合 @pytest.fixture 注入 headers
能力 支持情况
GET/POST/PUT/DELETE 请求测试 ✅ 有
登录 token 验证 ✅ 有
路由参数校验 ✅ 有
异步接口测试 ✅ 有(用 httpx.AsyncClient)
接口前后 setup 清理 ✅ 支持 fixture

点赞一下

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦