feat: 初始化考培练系统项目

- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
This commit is contained in:
111
2026-01-24 19:33:28 +08:00
commit 998211c483
1197 changed files with 228429 additions and 0 deletions

View File

@@ -0,0 +1,256 @@
"""
用户服务测试
"""
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