#单元测试:pytest 编写高覆盖率 Flask 测试
📂 所属阶段:第五阶段 — 高级进阶(性能与架构)
🔗 相关章节:Flask-Login 实战 · 环境搭建
#1. pytest 基础
#1.1 安装
pip install pytest pytest-flask#1.2 测试配置
# pytest.ini
[pytest]
testpaths = tests
python_files = test_*.py
python_functions = test_*
addopts = -v --tb=short#2. 测试夹具(Fixtures)
# conftest.py(全局测试配置)
import pytest
from app import create_app
from app.extensions import db
@pytest.fixture
def app():
"""创建测试应用"""
app = create_app("testing")
with app.app_context():
db.create_all()
yield app
db.drop_all()
@pytest.fixture
def client(app):
"""测试客户端"""
return app.test_client()
@pytest.fixture
def authenticated_client(client):
"""已登录的测试客户端"""
# 注册并登录
client.post("/auth/register", data={
"email": "test@example.com",
"password": "password123",
"username": "testuser"
})
client.post("/auth/login", data={
"email": "test@example.com",
"password": "password123"
})
return client#3. 测试视图
# tests/test_auth.py
def test_index_page(client):
"""测试首页"""
response = client.get("/")
assert response.status_code == 200
assert b"道满博客" in response.data
def test_login_page(client):
"""测试登录页"""
response = client.get("/auth/login")
assert response.status_code == 200
def test_login_success(client, app):
"""测试成功登录"""
# 先注册
client.post("/auth/register", data={
"email": "alice@example.com",
"password": "SecurePass123!",
"username": "alice"
})
# 再登录
response = client.post("/auth/login", data={
"email": "alice@example.com",
"password": "SecurePass123!"
}, follow_redirects=True)
assert response.status_code == 200
assert b"登录成功" in response.data
def test_login_wrong_password(client):
"""测试密码错误"""
response = client.post("/auth/login", data={
"email": "test@example.com",
"password": "wrongpassword"
})
assert response.status_code == 200
assert b"邮箱或密码错误" in response.data
def test_register_validation(client):
"""测试注册表单验证"""
response = client.post("/auth/register", data={
"email": "not-an-email",
"password": "123",
"username": "t"
})
assert response.status_code == 200
assert b"email" in response.data or b"邮箱" in response.data#4. 测试受保护路由
# tests/test_articles.py
def test_create_article_requires_login(client):
"""创建文章需要登录"""
response = client.post("/articles/create", data={
"title": "Test",
"content": "Test content"
})
assert response.status_code == 302 # 重定向到登录页
def test_create_article_authenticated(authenticated_client):
"""登录用户可以创建文章"""
response = authenticated_client.post("/articles/create", data={
"title": "Test Article",
"content": "This is a test article content."
}, follow_redirects=True)
assert response.status_code == 200
assert b"Test Article" in response.data#5. 测试覆盖率
pip install pytest-cov
# 运行测试并生成覆盖率报告
pytest --cov=app --cov-report=html
# 打开报告
# htmlcov/index.html
# 终端查看
pytest --cov=app --cov-report=term-missing#6. 小结
# pytest 速查
@pytest.fixture # 测试夹具
client.get(url) # GET 请求
client.post(url, data={...}) # POST 请求
response.status_code # 状态码
response.data # 响应体(bytes)
response.location # 重定向 URL
follow_redirects=True # 跟随重定向💡 最佳实践:测试驱动开发(TDD)——先写测试,再写功能代码。覆盖率目标:核心业务 80%+,简单函数 100%。
🔗 扩展阅读

