Files
fquiz/api/tests/test_user_create_error_messages.py
T
chengkai3 23db30d0f0 fix: [FL-199][拆分用户创建错误消息以明确失败原因]
将模糊的 409 错误消息 "User id/email/username already exists or default role missing"
拆分为三种具体的异常类型:

1. UserDuplicateError (409) - 用户ID/邮箱/用户名已存在
2. UserRoleAssignmentError (500) - 默认角色未配置或角色分配失败
3. UserCreateError (500) - 其他用户创建失败

改动内容:
- 在 user_service.py 中定义三个异常类
- 将 create_user 返回类型从 UserPublic | None 改为 UserPublic(抛出异常)
- 在 API 层捕获具体异常并返回对应的 HTTP 状态码和明确错误消息
- 更新和新增测试以验证错误消息准确性

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
2026-06-18 13:13:51 +08:00

138 lines
4.3 KiB
Python

"""
Test that user creation errors return specific, distinct error messages.
This test verifies the fix for FL-199 where the error message
"User id/email/username already exists or default role missing"
was too ambiguous to debug effectively.
"""
from __future__ import annotations
import os
import unittest
os.environ.setdefault("DATABASE_URL", "sqlite+pysqlite:///:memory:")
os.environ.setdefault("MINIO_ENABLED", "false")
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool
from api.app.core.database import Base
from api.app.schemas.user import UserCreateRequest
from api.app.services.user_service import (
UserDuplicateError,
create_user,
)
class UserCreateErrorMessageTest(unittest.TestCase):
"""Test that user creation returns specific error messages."""
def setUp(self) -> None:
self.engine = create_engine(
"sqlite+pysqlite://",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
self.SessionLocal = sessionmaker(
bind=self.engine,
autocommit=False,
autoflush=False,
expire_on_commit=False,
)
Base.metadata.create_all(bind=self.engine)
self.session = self.SessionLocal()
def tearDown(self) -> None:
self.session.close()
Base.metadata.drop_all(bind=self.engine)
self.engine.dispose()
def test_duplicate_user_id_error_message(self) -> None:
"""Test that duplicate user_id returns specific error message."""
create_user(
self.session,
UserCreateRequest(
user_id="duplicate_test",
email="user1@example.com",
username="User1",
password="password123",
),
actor_user_id="system",
)
with self.assertRaises(UserDuplicateError) as ctx:
create_user(
self.session,
UserCreateRequest(
user_id="duplicate_test",
email="user2@example.com",
username="User2",
password="password123",
),
actor_user_id="system",
)
self.assertIn("already exists", str(ctx.exception))
self.assertNotIn("default role", str(ctx.exception))
def test_duplicate_username_error_message(self) -> None:
"""Test that duplicate username returns specific error message."""
create_user(
self.session,
UserCreateRequest(
user_id="user1",
email="user1@example.com",
username="DuplicateUsername",
password="password123",
),
actor_user_id="system",
)
with self.assertRaises(UserDuplicateError) as ctx:
create_user(
self.session,
UserCreateRequest(
user_id="user2",
email="user2@example.com",
username="DuplicateUsername",
password="password123",
),
actor_user_id="system",
)
self.assertIn("already exists", str(ctx.exception))
self.assertNotIn("default role", str(ctx.exception))
def test_duplicate_email_error_message(self) -> None:
"""Test that duplicate email returns specific error message."""
create_user(
self.session,
UserCreateRequest(
user_id="user1",
email="duplicate@example.com",
username="User1",
password="password123",
),
actor_user_id="system",
)
with self.assertRaises(UserDuplicateError) as ctx:
create_user(
self.session,
UserCreateRequest(
user_id="user2",
email="duplicate@example.com",
username="User2",
password="password123",
),
actor_user_id="system",
)
self.assertIn("already exists", str(ctx.exception))
self.assertNotIn("default role", str(ctx.exception))
if __name__ == "__main__":
unittest.main()