- 从服务器拉取完整代码 - 按框架规范整理项目结构 - 配置 Drone CI 测试环境部署 - 包含后端(FastAPI)、前端(Vue3)、管理端 技术栈: Vue3 + TypeScript + FastAPI + MySQL
209 lines
6.9 KiB
Python
209 lines
6.9 KiB
Python
"""
|
|
认证模块单元测试
|
|
"""
|
|
import pytest
|
|
from httpx import AsyncClient
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.services.auth_service import AuthService
|
|
from app.schemas.auth import UserRegister
|
|
from app.core.security import verify_password, create_password_hash
|
|
from app.core.exceptions import InvalidCredentialsError, UsernameExistsError
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
class TestAuthService:
|
|
"""认证服务测试类"""
|
|
|
|
async def test_user_registration(self, db_session: AsyncSession, test_user_data):
|
|
"""测试用户注册"""
|
|
# 创建认证服务
|
|
auth_service = AuthService(db_session)
|
|
|
|
# 准备注册数据
|
|
register_data = UserRegister(**test_user_data)
|
|
|
|
# 注册用户
|
|
user = await auth_service.create_user(register_data)
|
|
|
|
# 验证用户创建成功
|
|
assert user.id is not None
|
|
assert user.username == test_user_data["username"]
|
|
assert user.email == test_user_data["email"]
|
|
assert user.is_active is True
|
|
assert user.role == "trainee"
|
|
|
|
# 验证密码已加密
|
|
assert user.password_hash != test_user_data["password"]
|
|
assert verify_password(test_user_data["password"], user.password_hash)
|
|
|
|
async def test_duplicate_username_registration(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user_data
|
|
):
|
|
"""测试重复用户名注册"""
|
|
auth_service = AuthService(db_session)
|
|
|
|
# 第一次注册
|
|
register_data = UserRegister(**test_user_data)
|
|
await auth_service.create_user(register_data)
|
|
|
|
# 尝试使用相同用户名再次注册
|
|
with pytest.raises(UsernameExistsError):
|
|
await auth_service.create_user(register_data)
|
|
|
|
async def test_user_login(self, db_session: AsyncSession, test_user_data):
|
|
"""测试用户登录"""
|
|
auth_service = AuthService(db_session)
|
|
|
|
# 先注册用户
|
|
register_data = UserRegister(**test_user_data)
|
|
user = await auth_service.create_user(register_data)
|
|
|
|
# 测试登录
|
|
authenticated_user = await auth_service.authenticate_user(
|
|
username=test_user_data["username"],
|
|
password=test_user_data["password"]
|
|
)
|
|
|
|
assert authenticated_user.id == user.id
|
|
assert authenticated_user.username == user.username
|
|
|
|
# 验证登录信息已更新
|
|
assert authenticated_user.login_count == "1"
|
|
assert authenticated_user.failed_login_count == "0"
|
|
assert authenticated_user.last_login is not None
|
|
|
|
async def test_login_with_email(self, db_session: AsyncSession, test_user_data):
|
|
"""测试使用邮箱登录"""
|
|
auth_service = AuthService(db_session)
|
|
|
|
# 注册用户
|
|
register_data = UserRegister(**test_user_data)
|
|
await auth_service.create_user(register_data)
|
|
|
|
# 使用邮箱登录
|
|
user = await auth_service.authenticate_user(
|
|
username=test_user_data["email"],
|
|
password=test_user_data["password"]
|
|
)
|
|
|
|
assert user.email == test_user_data["email"]
|
|
|
|
async def test_invalid_password_login(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user_data
|
|
):
|
|
"""测试错误密码登录"""
|
|
auth_service = AuthService(db_session)
|
|
|
|
# 注册用户
|
|
register_data = UserRegister(**test_user_data)
|
|
await auth_service.create_user(register_data)
|
|
|
|
# 尝试使用错误密码登录
|
|
with pytest.raises(InvalidCredentialsError):
|
|
await auth_service.authenticate_user(
|
|
username=test_user_data["username"],
|
|
password="WrongPassword123!"
|
|
)
|
|
|
|
async def test_token_creation(self, db_session: AsyncSession, test_user_data):
|
|
"""测试Token创建"""
|
|
auth_service = AuthService(db_session)
|
|
|
|
# 注册用户
|
|
register_data = UserRegister(**test_user_data)
|
|
user = await auth_service.create_user(register_data)
|
|
|
|
# 创建tokens
|
|
tokens = await auth_service.create_tokens_for_user(user)
|
|
|
|
assert "access_token" in tokens
|
|
assert "refresh_token" in tokens
|
|
assert tokens["token_type"] == "bearer"
|
|
assert tokens["expires_in"] > 0
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
class TestAuthAPI:
|
|
"""认证API测试类"""
|
|
|
|
async def test_register_endpoint(self, client: AsyncClient, test_user_data):
|
|
"""测试注册端点"""
|
|
response = await client.post(
|
|
"/api/v1/auth/register",
|
|
json=test_user_data
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["code"] == 200
|
|
assert data["message"] == "注册成功"
|
|
assert "access_token" in data["data"]
|
|
assert "refresh_token" in data["data"]
|
|
|
|
async def test_login_endpoint(self, client: AsyncClient, test_user_data):
|
|
"""测试登录端点"""
|
|
# 先注册
|
|
await client.post("/api/v1/auth/register", json=test_user_data)
|
|
|
|
# 测试登录
|
|
response = await client.post(
|
|
"/api/v1/auth/login",
|
|
data={
|
|
"username": test_user_data["username"],
|
|
"password": test_user_data["password"]
|
|
}
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["code"] == 200
|
|
assert "access_token" in data["data"]
|
|
|
|
async def test_refresh_token_endpoint(
|
|
self,
|
|
client: AsyncClient,
|
|
test_user_data
|
|
):
|
|
"""测试Token刷新端点"""
|
|
# 先注册并获取tokens
|
|
register_response = await client.post(
|
|
"/api/v1/auth/register",
|
|
json=test_user_data
|
|
)
|
|
tokens = register_response.json()["data"]
|
|
|
|
# 刷新token
|
|
response = await client.post(
|
|
"/api/v1/auth/refresh",
|
|
json={"refresh_token": tokens["refresh_token"]}
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "access_token" in data["data"]
|
|
assert data["data"]["access_token"] != tokens["access_token"]
|
|
|
|
async def test_logout_endpoint(self, client: AsyncClient):
|
|
"""测试登出端点"""
|
|
response = await client.post("/api/v1/auth/logout")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["message"] == "登出成功"
|
|
|
|
async def test_reset_password_request(self, client: AsyncClient):
|
|
"""测试重置密码请求"""
|
|
response = await client.post(
|
|
"/api/v1/auth/reset-password",
|
|
json={"email": "test@example.com"}
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "如果该邮箱已注册" in data["message"]
|