- 从服务器拉取完整代码 - 按框架规范整理项目结构 - 配置 Drone CI 测试环境部署 - 包含后端(FastAPI)、前端(Vue3)、管理端 技术栈: Vue3 + TypeScript + FastAPI + MySQL
257 lines
7.3 KiB
Python
257 lines
7.3 KiB
Python
"""
|
|
用户服务测试
|
|
"""
|
|
|
|
import pytest
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.exceptions import ConflictError, NotFoundError
|
|
from app.core.security import verify_password
|
|
from app.models.user import User
|
|
from app.schemas.user import UserCreate, UserFilter, UserUpdate
|
|
from app.services.user_service import UserService
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
class TestUserService:
|
|
"""用户服务测试类"""
|
|
|
|
async def test_create_user(self, db_session: AsyncSession):
|
|
"""测试创建用户"""
|
|
# 准备数据
|
|
user_in = UserCreate(
|
|
username="newuser",
|
|
email="newuser@example.com",
|
|
password="password123",
|
|
full_name="New User",
|
|
role="trainee",
|
|
)
|
|
|
|
# 创建用户
|
|
service = UserService(db_session)
|
|
user = await service.create_user(obj_in=user_in)
|
|
|
|
# 验证结果
|
|
assert user.username == "newuser"
|
|
assert user.email == "newuser@example.com"
|
|
assert user.full_name == "New User"
|
|
assert user.role == "trainee"
|
|
assert verify_password("password123", user.hashed_password)
|
|
|
|
async def test_create_user_duplicate_username(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
):
|
|
"""测试创建重复用户名的用户"""
|
|
user_in = UserCreate(
|
|
username=test_user.username, # 使用已存在的用户名
|
|
email="another@example.com",
|
|
password="password123",
|
|
)
|
|
|
|
service = UserService(db_session)
|
|
with pytest.raises(ConflictError) as exc_info:
|
|
await service.create_user(obj_in=user_in)
|
|
|
|
assert f"用户名 {test_user.username} 已存在" in str(exc_info.value)
|
|
|
|
async def test_create_user_duplicate_email(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
):
|
|
"""测试创建重复邮箱的用户"""
|
|
user_in = UserCreate(
|
|
username="anotheruser",
|
|
email=test_user.email, # 使用已存在的邮箱
|
|
password="password123",
|
|
)
|
|
|
|
service = UserService(db_session)
|
|
with pytest.raises(ConflictError) as exc_info:
|
|
await service.create_user(obj_in=user_in)
|
|
|
|
assert f"邮箱 {test_user.email} 已存在" in str(exc_info.value)
|
|
|
|
async def test_get_by_username(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
):
|
|
"""测试根据用户名获取用户"""
|
|
service = UserService(db_session)
|
|
user = await service.get_by_username(test_user.username)
|
|
|
|
assert user is not None
|
|
assert user.id == test_user.id
|
|
assert user.username == test_user.username
|
|
|
|
async def test_get_by_email(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
):
|
|
"""测试根据邮箱获取用户"""
|
|
service = UserService(db_session)
|
|
user = await service.get_by_email(test_user.email)
|
|
|
|
assert user is not None
|
|
assert user.id == test_user.id
|
|
assert user.email == test_user.email
|
|
|
|
async def test_update_user(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
):
|
|
"""测试更新用户"""
|
|
user_update = UserUpdate(
|
|
full_name="Updated Name",
|
|
bio="Updated bio",
|
|
)
|
|
|
|
service = UserService(db_session)
|
|
user = await service.update_user(
|
|
user_id=test_user.id,
|
|
obj_in=user_update,
|
|
)
|
|
|
|
assert user.full_name == "Updated Name"
|
|
assert user.bio == "Updated bio"
|
|
|
|
async def test_update_user_not_found(self, db_session: AsyncSession):
|
|
"""测试更新不存在的用户"""
|
|
user_update = UserUpdate(full_name="Updated Name")
|
|
|
|
service = UserService(db_session)
|
|
with pytest.raises(NotFoundError) as exc_info:
|
|
await service.update_user(
|
|
user_id=999,
|
|
obj_in=user_update,
|
|
)
|
|
|
|
assert "用户不存在" in str(exc_info.value)
|
|
|
|
async def test_update_password(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
):
|
|
"""测试更新密码"""
|
|
service = UserService(db_session)
|
|
|
|
# 更新密码
|
|
user = await service.update_password(
|
|
user_id=test_user.id,
|
|
old_password="testpass123",
|
|
new_password="newpass123",
|
|
)
|
|
|
|
# 验证新密码
|
|
assert verify_password("newpass123", user.hashed_password)
|
|
assert user.password_changed_at is not None
|
|
|
|
async def test_update_password_wrong_old(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
):
|
|
"""测试使用错误的旧密码更新"""
|
|
service = UserService(db_session)
|
|
|
|
with pytest.raises(ConflictError) as exc_info:
|
|
await service.update_password(
|
|
user_id=test_user.id,
|
|
old_password="wrongpass",
|
|
new_password="newpass123",
|
|
)
|
|
|
|
assert "旧密码错误" in str(exc_info.value)
|
|
|
|
async def test_get_users_with_filter(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
admin_user: User,
|
|
manager_user: User,
|
|
):
|
|
"""测试根据筛选条件获取用户"""
|
|
service = UserService(db_session)
|
|
|
|
# 测试角色筛选
|
|
filter_params = UserFilter(role="admin")
|
|
users, total = await service.get_users_with_filter(
|
|
skip=0,
|
|
limit=10,
|
|
filter_params=filter_params,
|
|
)
|
|
assert total == 1
|
|
assert users[0].id == admin_user.id
|
|
|
|
# 测试关键词搜索
|
|
filter_params = UserFilter(keyword="manager")
|
|
users, total = await service.get_users_with_filter(
|
|
skip=0,
|
|
limit=10,
|
|
filter_params=filter_params,
|
|
)
|
|
assert total == 1
|
|
assert users[0].id == manager_user.id
|
|
|
|
async def test_authenticate_username(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
):
|
|
"""测试使用用户名认证"""
|
|
service = UserService(db_session)
|
|
|
|
# 正确的密码
|
|
user = await service.authenticate(
|
|
username=test_user.username,
|
|
password="testpass123",
|
|
)
|
|
assert user is not None
|
|
assert user.id == test_user.id
|
|
|
|
# 错误的密码
|
|
user = await service.authenticate(
|
|
username=test_user.username,
|
|
password="wrongpass",
|
|
)
|
|
assert user is None
|
|
|
|
async def test_authenticate_email(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
):
|
|
"""测试使用邮箱认证"""
|
|
service = UserService(db_session)
|
|
|
|
user = await service.authenticate(
|
|
username=test_user.email,
|
|
password="testpass123",
|
|
)
|
|
assert user is not None
|
|
assert user.id == test_user.id
|
|
|
|
async def test_soft_delete(
|
|
self,
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
):
|
|
"""测试软删除用户"""
|
|
service = UserService(db_session)
|
|
|
|
# 软删除
|
|
user = await service.soft_delete(db_obj=test_user)
|
|
assert user.is_deleted is True
|
|
assert user.deleted_at is not None
|
|
|
|
# 验证无法通过常规方法获取
|
|
user = await service.get_by_id(test_user.id)
|
|
assert user is None
|
|
|