统一测试辅助函数到 conftest.py,消除代码重复

This commit is contained in:
2026-07-26 01:23:12 +08:00
parent 6b1f0d5f5f
commit 12d15878da
7 changed files with 276 additions and 421 deletions
+44 -96
View File
@@ -4,68 +4,14 @@ import pytest
from fastapi.testclient import TestClient
from app.routers import auth as auth_router
from tests.conftest import bearer
ADMIN_EMAIL = "admin@example.com"
ADMIN_PASSWORD = "admin-password-123"
# ---------------------------------------------------------------------------
# helpers
# ---------------------------------------------------------------------------
def _capture_email(monkeypatch) -> dict[str, str]:
captured: dict[str, str] = {}
async def capture(recipient: str, token: str) -> None:
captured["token"] = token
monkeypatch.setattr(auth_router, "send_confirmation_email", capture)
return captured
def _register(client: TestClient, email: str, password: str, username: str):
return client.post(
"/api/v1/auth/register",
json={"email": email, "password": password, "username": username},
)
def _confirm(client: TestClient, token: str):
return client.post("/api/v1/auth/confirm-email", json={"token": token})
def _login(client: TestClient, email: str, password: str):
return client.post(
"/api/v1/auth/login",
json={"email": email, "password": password},
)
def _register_and_confirm(
client: TestClient,
monkeypatch,
email: str,
password: str,
username: str,
) -> dict[str, str]:
captured = _capture_email(monkeypatch)
r = _register(client, email, password, username)
assert r.status_code == 201
token = captured.get("token")
assert token
cr = _confirm(client, token)
assert cr.status_code == 200
lr = _login(client, email, password)
assert lr.status_code == 200
body = lr.json()
return {"token": body["access_token"], "user_id": body["user"]["id"]}
def _login_as_user(client: TestClient, email: str, password: str) -> str:
r = _login(client, email, password)
return r.json()["access_token"]
from tests.conftest import (
bearer,
capture_email,
confirm_email,
login_user,
register_and_confirm,
register_user,
)
# ---------------------------------------------------------------------------
@@ -75,8 +21,8 @@ def _login_as_user(client: TestClient, email: str, password: str) -> str:
def test_register_success(client: TestClient, monkeypatch) -> None:
email = f"reg-{uuid.uuid4().hex[:8]}@example.com"
captured = _capture_email(monkeypatch)
r = _register(client, email, "regpassword", "注册测试")
captured = capture_email(monkeypatch)
r = register_user(client, email, "regpassword", "注册测试")
assert r.status_code == 201
assert r.json()["message"] == "注册成功,请查收确认邮件"
assert "token" in captured
@@ -84,8 +30,8 @@ def test_register_success(client: TestClient, monkeypatch) -> None:
def test_register_duplicate_email(client: TestClient, monkeypatch) -> None:
email = f"dup-{uuid.uuid4().hex[:8]}@example.com"
_register(client, email, "firstpass", "第一个用户")
r = _register(client, email, "secondpass", "第二个用户")
register_user(client, email, "firstpass", "第一个用户")
r = register_user(client, email, "secondpass", "第二个用户")
assert r.status_code == 409
assert "该邮箱已被注册" == r.json()["detail"]
@@ -93,24 +39,24 @@ def test_register_duplicate_email(client: TestClient, monkeypatch) -> None:
def test_register_duplicate_username(client: TestClient, monkeypatch) -> None:
email_a = f"dupname-a-{uuid.uuid4().hex[:8]}@example.com"
email_b = f"dupname-b-{uuid.uuid4().hex[:8]}@example.com"
_register(client, email_a, "passA123", "同名用户")
r = _register(client, email_b, "passB123", "同名用户")
register_user(client, email_a, "passA123", "同名用户")
r = register_user(client, email_b, "passB123", "同名用户")
assert r.status_code == 409
assert "这个昵称已经被使用" == r.json()["detail"]
def test_register_short_password(client: TestClient) -> None:
r = _register(client, f"s-{uuid.uuid4().hex[:8]}@e.com", "1234567", "短密码")
r = register_user(client, f"s-{uuid.uuid4().hex[:8]}@e.com", "1234567", "短密码")
assert r.status_code == 422
def test_register_short_username(client: TestClient) -> None:
r = _register(client, f"s-{uuid.uuid4().hex[:8]}@e.com", "pass12345", "A")
r = register_user(client, f"s-{uuid.uuid4().hex[:8]}@e.com", "pass12345", "A")
assert r.status_code == 422
def test_register_invalid_email(client: TestClient) -> None:
r = _register(client, "not-an-email", "pass12345", "坏邮箱")
r = register_user(client, "not-an-email", "pass12345", "坏邮箱")
assert r.status_code == 422
@@ -121,18 +67,18 @@ def test_register_invalid_email(client: TestClient) -> None:
def test_confirm_email_valid(client: TestClient, monkeypatch) -> None:
email = f"confirm-{uuid.uuid4().hex[:8]}@example.com"
captured = _capture_email(monkeypatch)
r = _register(client, email, "confirmpass", "确认测试")
captured = capture_email(monkeypatch)
r = register_user(client, email, "confirmpass", "确认测试")
assert r.status_code == 201
token = captured.get("token")
assert token
cr = _confirm(client, token)
cr = confirm_email(client, token)
assert cr.status_code == 200
assert cr.json()["message"] == "邮箱确认成功"
def test_confirm_email_invalid_token(client: TestClient) -> None:
r = _confirm(client, "not-a-valid-token-at-all-never")
r = confirm_email(client, "not-a-valid-token-at-all-never")
assert r.status_code == 400
assert "无效" in r.json()["detail"]
@@ -144,49 +90,51 @@ def test_confirm_email_invalid_token(client: TestClient) -> None:
def test_login_success(client: TestClient, monkeypatch) -> None:
email = f"login-{uuid.uuid4().hex[:8]}@example.com"
info = _register_and_confirm(client, monkeypatch, email, "loginpass", "登录测试")
info = register_and_confirm(client, monkeypatch, email, "loginpass", "登录测试")
assert info["token"]
assert info["user_id"]
def test_login_wrong_password(client: TestClient, monkeypatch) -> None:
email = f"loginfail-{uuid.uuid4().hex[:8]}@example.com"
_register_and_confirm(client, monkeypatch, email, "rightpass", "登录失败")
r = _login(client, email, "wrongpass")
register_and_confirm(client, monkeypatch, email, "rightpass", "登录失败")
r = login_user(client, email, "wrongpass")
assert r.status_code == 401
assert "邮箱或密码错误" == r.json()["detail"]
def test_login_nonexistent_email(client: TestClient) -> None:
r = _login(client, "nobody@example.com", "whatever")
r = login_user(client, "nobody@example.com", "whatever")
assert r.status_code == 401
def test_login_unverified_email(client: TestClient, monkeypatch) -> None:
email = f"unverified-{uuid.uuid4().hex[:8]}@example.com"
_capture_email(monkeypatch)
_register(client, email, "unverified", "未确认")
r = _login(client, email, "unverified")
capture_email(monkeypatch)
register_user(client, email, "unverified", "未确认")
r = login_user(client, email, "unverified")
assert r.status_code == 403
assert "邮箱尚未确认" == r.json()["detail"]
def test_login_disabled_user(client: TestClient, monkeypatch) -> None:
from tests.conftest import ADMIN_EMAIL, ADMIN_PASSWORD
email = f"disabled-{uuid.uuid4().hex[:8]}@example.com"
info = _register_and_confirm(client, monkeypatch, email, "disabled", "禁用测试")
admin_token = _login_as_user(client, ADMIN_EMAIL, ADMIN_PASSWORD)
info = register_and_confirm(client, monkeypatch, email, "disabled", "禁用测试")
admin_tok = login_user(client, ADMIN_EMAIL, ADMIN_PASSWORD).json()["access_token"]
client.patch(
f"/api/v1/admin/users/{info['user_id']}",
headers=bearer(admin_token),
headers=bearer(admin_tok),
json={"is_disabled": True},
)
r = _login(client, email, "disabled")
r = login_user(client, email, "disabled")
assert r.status_code == 403
assert "账号已被禁用" == r.json()["detail"]
client.patch(
f"/api/v1/admin/users/{info['user_id']}",
headers=bearer(admin_token),
headers=bearer(admin_tok),
json={"is_disabled": False},
)
@@ -198,7 +146,7 @@ def test_login_disabled_user(client: TestClient, monkeypatch) -> None:
def test_refresh_success(client: TestClient, monkeypatch) -> None:
email = f"refresh-{uuid.uuid4().hex[:8]}@example.com"
_register_and_confirm(client, monkeypatch, email, "refreshpass", "刷新测试")
register_and_confirm(client, monkeypatch, email, "refreshpass", "刷新测试")
r = client.post("/api/v1/auth/refresh")
assert r.status_code == 200
assert "access_token" in r.json()
@@ -237,7 +185,7 @@ def test_logout(client: TestClient) -> None:
def test_forgot_password_existing_email(client: TestClient, monkeypatch) -> None:
email = f"forgot-{uuid.uuid4().hex[:8]}@example.com"
_register_and_confirm(client, monkeypatch, email, "forgotpass", "忘记密码")
register_and_confirm(client, monkeypatch, email, "forgotpass", "忘记密码")
captured = {}
monkeypatch.setattr(auth_router, "send_password_reset_email", captured.__setitem__)
r = client.post("/api/v1/auth/forgot-password", json={"email": email})
@@ -252,7 +200,7 @@ def test_forgot_password_nonexistent_email(client: TestClient) -> None:
def test_reset_password_valid(client: TestClient, monkeypatch) -> None:
email = f"reset-{uuid.uuid4().hex[:8]}@example.com"
_register_and_confirm(client, monkeypatch, email, "oldpass12", "重置密码")
register_and_confirm(client, monkeypatch, email, "oldpass12", "重置密码")
captured = {}
monkeypatch.setattr(auth_router, "send_password_reset_email", lambda r, t: captured.update(token=t))
@@ -267,9 +215,9 @@ def test_reset_password_valid(client: TestClient, monkeypatch) -> None:
assert r.status_code == 200
assert r.json()["message"] == "密码已重置,请重新登录"
r = _login(client, email, "oldpass12")
r = login_user(client, email, "oldpass12")
assert r.status_code == 401
r = _login(client, email, "newpass12")
r = login_user(client, email, "newpass12")
assert r.status_code == 200
@@ -289,7 +237,7 @@ def test_reset_password_invalid_token(client: TestClient) -> None:
def test_change_password(client: TestClient, monkeypatch) -> None:
email = f"chpw-{uuid.uuid4().hex[:8]}@example.com"
info = _register_and_confirm(client, monkeypatch, email, "oldpass12", "改密")
info = register_and_confirm(client, monkeypatch, email, "oldpass12", "改密")
r = client.patch(
"/api/v1/auth/password",
headers=bearer(info["token"]),
@@ -298,9 +246,9 @@ def test_change_password(client: TestClient, monkeypatch) -> None:
assert r.status_code == 200
assert "access_token" in r.json()
r = _login(client, email, "oldpass12")
r = login_user(client, email, "oldpass12")
assert r.status_code == 401
r = _login(client, email, "updatedpass12")
r = login_user(client, email, "updatedpass12")
assert r.status_code == 200
@@ -311,7 +259,7 @@ def test_change_password(client: TestClient, monkeypatch) -> None:
def test_me(client: TestClient, monkeypatch) -> None:
email = f"me-{uuid.uuid4().hex[:8]}@example.com"
info = _register_and_confirm(client, monkeypatch, email, "mepass12!", "我的信息")
info = register_and_confirm(client, monkeypatch, email, "mepass12!", "我的信息")
r = client.get("/api/v1/auth/me", headers=bearer(info["token"]))
assert r.status_code == 200
body = r.json()