生成代码工程

This commit is contained in:
root 2026-05-12 13:03:18 +08:00
parent ef4dcc8a43
commit 32d28dcae2
11 changed files with 9362 additions and 2 deletions

123
README.md
View File

@ -1,3 +1,122 @@
# 多智能体协作开发平台项目
# User Management Service - 用户管理服务
基于当前产品进行研发实施等
基于 FastAPI 构建的用户管理单体服务,采用内存假数据存储,无需外部依赖。
## 功能特性
- ✅ 用户注册POST /api/users
- ✅ 获取用户列表GET /api/users
- ✅ 获取单个用户GET /api/users/{user_id}
- ✅ 更新用户信息PUT /api/users/{user_id}
- ✅ 删除用户DELETE /api/users/{user_id}
- ✅ 用户登录验证POST /api/users/login
- ✅ 健康检查GET /health
## 项目结构
```
project-files/
├── requirements.txt
├── README.md
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI 应用入口及路由
│ ├── models.py # 数据模型定义
│ ├── services.py # 业务逻辑层
│ └── database.py # 内存数据库(假数据)
└── tests/
└── test_basic.py # 基础单元测试
```
## 环境要求
- Python >= 3.11
## 安装依赖
```bash
cd codegen-runs/codegen_216c32ee7c414070891e6bd4259621a9
pip install -r requirements.txt
```
## 启动服务
方式一:直接启动
```bash
python app/main.py
```
方式二:使用 uvicorn
```bash
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
```
服务启动后访问:
- API 文档Swagger UIhttp://localhost:8000/docs
- API 文档Redochttp://localhost:8000/redoc
- 健康检查http://localhost:8000/health
## 运行测试
```bash
cd codegen-runs/codegen_216c32ee7c414070891e6bd4259621a9
pytest -v
```
## API 接口说明
### 健康检查
```
GET /health
```
### 用户注册
```
POST /api/users
Content-Type: application/json
{
"username": "alice",
"email": "alice@example.com",
"password": "secret123"
}
```
### 获取用户列表
```
GET /api/users?skip=0&limit=10
```
### 获取单个用户
```
GET /api/users/{user_id}
```
### 更新用户
```
PUT /api/users/{user_id}
Content-Type: application/json
{
"username": "alice_new",
"email": "alice_new@example.com"
}
```
### 删除用户
```
DELETE /api/users/{user_id}
```
### 用户登录
```
POST /api/users/login
Content-Type: application/json
{
"username": "alice",
"password": "secret123"
}
```

1
app/__init__.py Normal file
View File

@ -0,0 +1 @@
# User Management Service - 用户管理服务应用包

179
app/database.py Normal file
View File

@ -0,0 +1,179 @@
"""用户管理服务 - 内存数据库模块。
使用线程安全的 dict 模拟数据库存储提供基础的 CRUD 操作
所有数据存储在内存中服务重启后数据会丢失
"""
import threading
import uuid
from datetime import datetime
from typing import Optional
from app.models import UserInDB
class InMemoryDatabase:
"""基于内存的简易数据库,线程安全。
使用 dict 存储用户数据key 为用户 IDvalue UserInDB 对象
同时维护 username -> user_id 的映射表以支持按用户名查询
Attributes:
_users: 用户数据存储格式 {user_id: UserInDB}
_username_index: 用户名索引格式 {username: user_id}
_lock: 线程锁保证并发安全
"""
def __init__(self):
"""初始化内存数据库,并插入预设的假数据。"""
self._users: dict[str, UserInDB] = {}
self._username_index: dict[str, str] = {}
self._lock = threading.Lock()
self._init_seed_data()
def _init_seed_data(self):
"""初始化预设的假数据,用于演示和测试。"""
seed_users = [
{
"id": "user-001",
"username": "alice",
"email": "alice@example.com",
"hashed_password": "e99a18c428cb38d5f260853678922e03", # hash of "abc123"
"created_at": "2024-01-15T08:30:00",
"is_active": True,
},
{
"id": "user-002",
"username": "bob",
"email": "bob@example.com",
"hashed_password": "e99a18c428cb38d5f260853678922e03",
"created_at": "2024-02-20T10:15:00",
"is_active": True,
},
{
"id": "user-003",
"username": "charlie",
"email": "charlie@example.com",
"hashed_password": "e99a18c428cb38d5f260853678922e03",
"created_at": "2024-03-10T14:45:00",
"is_active": True,
},
]
for user_data in seed_users:
user = UserInDB(**user_data)
self._users[user.id] = user
self._username_index[user.username] = user.id
def insert_user(self, user: UserInDB) -> UserInDB:
"""插入一个新用户。
Args:
user: 要插入的用户对象
Returns:
插入后的用户对象
"""
with self._lock:
self._users[user.id] = user
self._username_index[user.username] = user.id
return user
def get_user_by_id(self, user_id: str) -> Optional[UserInDB]:
"""根据用户 ID 查询用户。
Args:
user_id: 用户唯一标识
Returns:
如果找到则返回用户对象否则返回 None
"""
with self._lock:
return self._users.get(user_id)
def get_user_by_username(self, username: str) -> Optional[UserInDB]:
"""根据用户名查询用户。
Args:
username: 用户名
Returns:
如果找到则返回用户对象否则返回 None
"""
with self._lock:
user_id = self._username_index.get(username)
if user_id is None:
return None
return self._users.get(user_id)
def get_all_users(self, skip: int = 0, limit: int = 10) -> list[UserInDB]:
"""获取用户列表,支持分页。
Args:
skip: 跳过的记录数默认 0
limit: 返回的最大记录数默认 10
Returns:
用户对象列表
"""
with self._lock:
all_users = list(self._users.values())
return all_users[skip : skip + limit]
def update_user(self, user_id: str, update_data: dict) -> Optional[UserInDB]:
"""更新用户信息。
Args:
user_id: 要更新的用户 ID
update_data: 要更新的字段字典
Returns:
更新后的用户对象如果用户不存在则返回 None
"""
with self._lock:
user = self._users.get(user_id)
if user is None:
return None
# 如果更新了用户名,需要同步更新索引
old_username = user.username
new_username = update_data.get("username")
if new_username and new_username != old_username:
# 检查新用户名是否已被占用
if new_username in self._username_index:
return None # 用户名冲突
del self._username_index[old_username]
self._username_index[new_username] = user_id
updated_user = user.model_copy(update=update_data)
self._users[user_id] = updated_user
return updated_user
def delete_user(self, user_id: str) -> bool:
"""删除用户。
Args:
user_id: 要删除的用户 ID
Returns:
删除成功返回 True用户不存在返回 False
"""
with self._lock:
user = self._users.get(user_id)
if user is None:
return False
del self._users[user_id]
del self._username_index[user.username]
return True
def count_users(self) -> int:
"""统计用户总数。
Returns:
用户数量
"""
with self._lock:
return len(self._users)
# 全局单例数据库实例
db = InMemoryDatabase()

285
app/main.py Normal file
View File

@ -0,0 +1,285 @@
"""用户管理服务 - FastAPI 应用入口模块。
提供用户注册登录查询更新删除等 RESTful API 接口
"""
from typing import Optional
from fastapi import FastAPI, HTTPException, Query, status
from fastapi.middleware.cors import CORSMiddleware
from app.models import (
ErrorResponse,
SuccessResponse,
UserCreate,
UserLogin,
UserResponse,
UserUpdate,
)
from app.services import (
create_user,
delete_user,
get_all_users,
get_user_by_id,
get_user_count,
login,
update_user,
)
# 创建 FastAPI 应用实例
app = FastAPI(
title="User Management API",
description="用户管理服务 - 提供用户注册、登录、CRUD 等基础功能",
version="1.0.0",
)
# 添加 CORS 中间件,允许跨域访问
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/health", tags=["系统"])
async def health_check():
"""健康检查接口。
Returns:
服务运行状态信息
"""
return {
"status": "ok",
"service": "user-management-service",
"version": "1.0.0",
"total_users": get_user_count(),
}
# ──────────────────────────────────────────────
# 用户管理 API
# ──────────────────────────────────────────────
@app.post(
"/api/users",
response_model=UserResponse,
status_code=status.HTTP_201_CREATED,
tags=["用户管理"],
summary="注册新用户",
description="创建一个新的用户账户,需要提供用户名、邮箱和密码。",
responses={
201: {"description": "用户创建成功", "model": UserResponse},
400: {"description": "请求数据不合法", "model": ErrorResponse},
409: {"description": "用户名或邮箱已被占用", "model": ErrorResponse},
},
)
async def api_create_user(user_data: UserCreate):
"""用户注册接口。
Args:
user_data: 用户注册信息用户名邮箱密码
Returns:
创建成功的用户信息
Raises:
HTTPException: 当输入验证失败或用户名/邮箱已存在时抛出
"""
try:
return create_user(user_data)
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=str(e),
)
@app.get(
"/api/users",
response_model=list[UserResponse],
tags=["用户管理"],
summary="获取用户列表",
description="分页获取所有用户信息列表。",
)
async def api_get_users(
skip: int = Query(0, ge=0, description="跳过的记录数"),
limit: int = Query(10, ge=1, le=100, description="每页数量"),
):
"""获取用户列表接口。
Args:
skip: 跳过的记录数默认 0
limit: 每页数量默认 10最大 100
Returns:
用户信息列表
"""
return get_all_users(skip, limit)
@app.get(
"/api/users/{user_id}",
response_model=UserResponse,
tags=["用户管理"],
summary="获取单个用户",
description="根据用户 ID 获取指定用户的详细信息。",
responses={
200: {"description": "成功获取用户信息", "model": UserResponse},
404: {"description": "用户不存在", "model": ErrorResponse},
},
)
async def api_get_user(user_id: str):
"""获取单个用户接口。
Args:
user_id: 用户 ID
Returns:
用户详细信息
Raises:
HTTPException: 当用户不存在时抛出 404
"""
user = get_user_by_id(user_id)
if user is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"用户 '{user_id}' 不存在",
)
return user
@app.put(
"/api/users/{user_id}",
response_model=UserResponse,
tags=["用户管理"],
summary="更新用户信息",
description="更新指定用户的用户名和/或邮箱。",
responses={
200: {"description": "更新成功", "model": UserResponse},
404: {"description": "用户不存在", "model": ErrorResponse},
409: {"description": "新用户名已被占用", "model": ErrorResponse},
},
)
async def api_update_user(user_id: str, update_data: UserUpdate):
"""更新用户信息接口。
Args:
user_id: 要更新的用户 ID
update_data: 待更新的字段
Returns:
更新后的用户信息
Raises:
HTTPException: 用户不存在抛出 404用户名冲突抛出 409
"""
try:
result = update_user(user_id, update_data)
if result is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"用户 '{user_id}' 不存在",
)
return result
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=str(e),
)
@app.delete(
"/api/users/{user_id}",
response_model=SuccessResponse,
tags=["用户管理"],
summary="删除用户",
description="删除指定的用户账户。",
responses={
200: {"description": "删除成功", "model": SuccessResponse},
404: {"description": "用户不存在", "model": ErrorResponse},
},
)
async def api_delete_user(user_id: str):
"""删除用户接口。
Args:
user_id: 要删除的用户 ID
Returns:
删除成功消息
Raises:
HTTPException: 用户不存在时抛出 404
"""
success = delete_user(user_id)
if not success:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"用户 '{user_id}' 不存在",
)
return {"message": f"用户 '{user_id}' 已成功删除"}
# ──────────────────────────────────────────────
# 用户登录 API
# ──────────────────────────────────────────────
@app.post(
"/api/users/login",
response_model=UserResponse,
tags=["用户管理"],
summary="用户登录",
description="使用用户名和密码进行登录验证。",
responses={
200: {"description": "登录成功", "model": UserResponse},
401: {"description": "用户名或密码错误", "model": ErrorResponse},
},
)
async def api_login(login_data: UserLogin):
"""用户登录接口。
Args:
login_data: 登录凭证用户名和密码
Returns:
登录成功的用户信息
Raises:
HTTPException: 用户名或密码错误时抛出 401
"""
user = login(login_data)
if user is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="用户名或密码错误",
)
return user
# ──────────────────────────────────────────────
# 应用入口
# ──────────────────────────────────────────────
def main():
"""启动 FastAPI 应用的入口函数。
使用 uvicorn 运行服务监听 0.0.0.0:8000
"""
import uvicorn
uvicorn.run(
"app.main:app",
host="0.0.0.0",
port=8000,
reload=True,
)
if __name__ == "__main__":
main()

105
app/models.py Normal file
View File

@ -0,0 +1,105 @@
"""用户管理服务 - 数据模型定义模块。
定义系统中使用的 Pydantic 模型包括请求体和响应体的数据结构
"""
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, EmailStr, Field
class UserCreate(BaseModel):
"""用户创建请求模型。
Attributes:
username: 用户名3-50个字符
email: 邮箱地址
password: 密码6-100个字符
"""
username: str = Field(..., min_length=3, max_length=50, description="用户名")
email: str = Field(..., description="邮箱地址")
password: str = Field(..., min_length=6, max_length=100, description="密码")
class UserUpdate(BaseModel):
"""用户更新请求模型。
Attributes:
username: 可选用户名
email: 可选邮箱地址
"""
username: Optional[str] = Field(None, min_length=3, max_length=50, description="用户名")
email: Optional[str] = Field(None, description="邮箱地址")
class UserLogin(BaseModel):
"""用户登录请求模型。
Attributes:
username: 用户名
password: 密码
"""
username: str = Field(..., description="用户名")
password: str = Field(..., description="密码")
class UserResponse(BaseModel):
"""用户信息响应模型。
Attributes:
id: 用户唯一标识
username: 用户名
email: 邮箱地址
created_at: 创建时间
is_active: 是否激活
"""
id: str = Field(..., description="用户ID")
username: str = Field(..., description="用户名")
email: str = Field(..., description="邮箱地址")
created_at: str = Field(..., description="创建时间")
is_active: bool = Field(default=True, description="是否激活")
class UserInDB(BaseModel):
"""数据库中的用户模型(包含密码哈希)。
Attributes:
id: 用户唯一标识
username: 用户名
email: 邮箱地址
hashed_password: 密码哈希值
created_at: 创建时间
is_active: 是否激活
"""
id: str = Field(..., description="用户ID")
username: str = Field(..., description="用户名")
email: str = Field(..., description="邮箱地址")
hashed_password: str = Field(..., description="密码哈希值")
created_at: str = Field(..., description="创建时间")
is_active: bool = Field(default=True, description="是否激活")
class ErrorResponse(BaseModel):
"""错误响应模型。
Attributes:
detail: 错误详情描述
"""
detail: str = Field(..., description="错误描述")
class SuccessResponse(BaseModel):
"""成功响应模型。
Attributes:
message: 成功消息
"""
message: str = Field(..., description="成功消息")

193
app/services.py Normal file
View File

@ -0,0 +1,193 @@
"""用户管理服务 - 业务逻辑层模块。
封装用户相关的业务逻辑包括用户注册登录验证信息查询与更新等
"""
import hashlib
import uuid
from datetime import datetime
from typing import Optional
from app.database import db
from app.models import UserCreate, UserInDB, UserLogin, UserResponse, UserUpdate
def _hash_password(password: str) -> str:
"""对密码进行哈希处理。
使用 SHA-256 对密码进行哈希演示用途生产环境应使用 bcrypt 等安全算法
Args:
password: 原始密码字符串
Returns:
密码的十六进制哈希值
"""
return hashlib.sha256(password.encode("utf-8")).hexdigest()
def _user_to_response(user: UserInDB) -> UserResponse:
"""将数据库用户模型转换为响应模型。
Args:
user: 数据库中的用户对象
Returns:
对外暴露的用户响应对象不包含密码
"""
return UserResponse(
id=user.id,
username=user.username,
email=user.email,
created_at=user.created_at,
is_active=user.is_active,
)
def create_user(user_data: UserCreate) -> UserResponse:
"""注册新用户。
执行业务校验检查用户名是否已被占用然后创建用户并存储
Args:
user_data: 用户注册请求数据
Returns:
创建成功的用户响应对象
Raises:
ValueError: 如果用户名或邮箱已被占用
"""
# 检查用户名是否已存在
existing_user = db.get_user_by_username(user_data.username)
if existing_user is not None:
raise ValueError(f"用户名 '{user_data.username}' 已被占用")
# 检查邮箱是否已存在(遍历检查)
all_users = db.get_all_users(0, 1000)
for user in all_users:
if user.email == user_data.email:
raise ValueError(f"邮箱 '{user_data.email}' 已被注册")
now = datetime.now().isoformat(timespec="seconds")
user_id = f"user-{uuid.uuid4().hex[:8]}"
user_in_db = UserInDB(
id=user_id,
username=user_data.username,
email=user_data.email,
hashed_password=_hash_password(user_data.password),
created_at=now,
is_active=True,
)
db.insert_user(user_in_db)
return _user_to_response(user_in_db)
def get_user_by_id(user_id: str) -> Optional[UserResponse]:
"""根据用户 ID 获取用户信息。
Args:
user_id: 用户 ID
Returns:
用户响应对象如果不存在则返回 None
"""
user = db.get_user_by_id(user_id)
if user is None:
return None
return _user_to_response(user)
def get_user_by_username(username: str) -> Optional[UserResponse]:
"""根据用户名获取用户信息。
Args:
username: 用户名
Returns:
用户响应对象如果不存在则返回 None
"""
user = db.get_user_by_username(username)
if user is None:
return None
return _user_to_response(user)
def get_all_users(skip: int = 0, limit: int = 10) -> list[UserResponse]:
"""获取用户列表(分页)。
Args:
skip: 跳过的记录数
limit: 每页数量
Returns:
用户响应对象列表
"""
users = db.get_all_users(skip, limit)
return [_user_to_response(u) for u in users]
def update_user(user_id: str, update_data: UserUpdate) -> Optional[UserResponse]:
"""更新用户信息。
Args:
user_id: 要更新的用户 ID
update_data: 待更新的字段
Returns:
更新后的用户响应对象
Raises:
ValueError: 如果新用户名已被占用
"""
update_dict = update_data.model_dump(exclude_none=True)
if not update_dict:
return get_user_by_id(user_id)
updated_user = db.update_user(user_id, update_dict)
if updated_user is None:
return None
return _user_to_response(updated_user)
def delete_user(user_id: str) -> bool:
"""删除用户。
Args:
user_id: 要删除的用户 ID
Returns:
删除成功返回 True
"""
return db.delete_user(user_id)
def login(login_data: UserLogin) -> Optional[UserResponse]:
"""用户登录验证。
验证用户名和密码是否匹配
Args:
login_data: 登录请求数据用户名和密码
Returns:
登录成功返回用户信息失败返回 None
"""
user = db.get_user_by_username(login_data.username)
if user is None:
return None
if user.hashed_password != _hash_password(login_data.password):
return None
return _user_to_response(user)
def get_user_count() -> int:
"""获取用户总数。
Returns:
系统中用户的总数量
"""
return db.count_users()

8193
events.ndjson Normal file

File diff suppressed because one or more lines are too long

31
generation.json Normal file
View File

@ -0,0 +1,31 @@
{
"projectId": 40,
"generationId": "codegen_216c32ee7c414070891e6bd4259621a9",
"language": "python",
"status": "completed",
"fileIds": [],
"outputDir": "D:\\workspace\\agent\\DocumentGenerateAgent\\agents\\ai_agents\\project-files\\codegen-runs\\codegen_216c32ee7c414070891e6bd4259621a9",
"relativeOutputDir": "codegen-runs/codegen_216c32ee7c414070891e6bd4259621a9",
"generatedFiles": [
"README.md",
"app/__init__.py",
"app/database.py",
"app/main.py",
"app/models.py",
"app/services.py",
"events.ndjson",
"requirements.txt",
"tests/__init__.py",
"tests/test_basic.py"
],
"analysisSummary": "未提供参考文件请仅根据用户自然语言描述生成Python工程。",
"eventLogFile": "D:\\workspace\\agent\\DocumentGenerateAgent\\agents\\ai_agents\\project-files\\codegen-runs\\codegen_216c32ee7c414070891e6bd4259621a9\\events.ndjson",
"repoSettings": {
"username": "root",
"password": "pAssW0rd",
"repoUrl": "http://47.108.255.216:3000/root/more_agent.git",
"branch": "main"
},
"repoUrl": "http://47.108.255.216:3000/root/more_agent.git",
"branch": "main"
}

5
requirements.txt Normal file
View File

@ -0,0 +1,5 @@
fastapi==0.104.1
uvicorn==0.24.0
pydantic==2.5.2
pytest==7.4.3
httpx==0.25.2

1
tests/__init__.py Normal file
View File

@ -0,0 +1 @@
# 测试包

248
tests/test_basic.py Normal file
View File

@ -0,0 +1,248 @@
"""用户管理服务 - 基础单元测试模块。
使用 pytest httpx API 接口进行测试
"""
import pytest
from fastapi.testclient import TestClient
from app.main import app
from app.database import db
# ──────────────────────────────────────────────
# 测试客户端
# ──────────────────────────────────────────────
@pytest.fixture(autouse=True)
def reset_database():
"""每个测试用例执行前重置数据库状态。
保存原始数据并在测试后恢复避免测试间的数据污染
"""
# 清空数据库并重新初始化种子数据
db._users.clear()
db._username_index.clear()
db._init_seed_data()
yield
client = TestClient(app)
# ──────────────────────────────────────────────
# 健康检查测试
# ──────────────────────────────────────────────
class TestHealthCheck:
"""健康检查接口测试类。"""
def test_health_check_returns_ok(self):
"""测试健康检查接口返回状态 ok。"""
response = client.get("/health")
assert response.status_code == 200
data = response.json()
assert data["status"] == "ok"
assert data["service"] == "user-management-service"
assert data["total_users"] >= 3
# ──────────────────────────────────────────────
# 用户创建测试
# ──────────────────────────────────────────────
class TestCreateUser:
"""用户注册接口测试类。"""
def test_create_user_success(self):
"""测试成功创建用户。"""
response = client.post(
"/api/users",
json={
"username": "newuser",
"email": "newuser@example.com",
"password": "password123",
},
)
assert response.status_code == 201
data = response.json()
assert data["username"] == "newuser"
assert data["email"] == "newuser@example.com"
assert data["is_active"] is True
assert "id" in data
assert "created_at" in data
def test_create_user_duplicate_username(self):
"""测试创建重复用户名应返回 409。"""
response = client.post(
"/api/users",
json={
"username": "alice",
"email": "alice2@example.com",
"password": "password123",
},
)
assert response.status_code == 409
assert "已被占用" in response.json()["detail"]
def test_create_user_duplicate_email(self):
"""测试创建重复邮箱应返回 409。"""
response = client.post(
"/api/users",
json={
"username": "alice2",
"email": "alice@example.com",
"password": "password123",
},
)
assert response.status_code == 409
assert "已被注册" in response.json()["detail"]
def test_create_user_validation_error(self):
"""测试用户名太短应返回 422。"""
response = client.post(
"/api/users",
json={
"username": "ab",
"email": "test@example.com",
"password": "password123",
},
)
assert response.status_code == 422
# ──────────────────────────────────────────────
# 用户查询测试
# ──────────────────────────────────────────────
class TestGetUsers:
"""用户查询接口测试类。"""
def test_get_all_users(self):
"""测试获取所有用户(分页)。"""
response = client.get("/api/users?skip=0&limit=10")
assert response.status_code == 200
data = response.json()
assert len(data) >= 3
# 验证返回的字段不包含密码
for user in data:
assert "password" not in user
assert "hashed_password" not in user
def test_get_user_by_id_success(self):
"""测试通过 ID 获取用户成功。"""
response = client.get("/api/users/user-001")
assert response.status_code == 200
data = response.json()
assert data["username"] == "alice"
assert data["email"] == "alice@example.com"
def test_get_user_by_id_not_found(self):
"""测试获取不存在的用户返回 404。"""
response = client.get("/api/users/user-999")
assert response.status_code == 404
def test_get_users_pagination(self):
"""测试分页参数生效。"""
response = client.get("/api/users?skip=0&limit=1")
assert response.status_code == 200
data = response.json()
assert len(data) == 1
# ──────────────────────────────────────────────
# 用户更新测试
# ──────────────────────────────────────────────
class TestUpdateUser:
"""用户更新接口测试类。"""
def test_update_username_success(self):
"""测试成功更新用户名。"""
response = client.put(
"/api/users/user-001",
json={"username": "alice_updated"},
)
assert response.status_code == 200
data = response.json()
assert data["username"] == "alice_updated"
def test_update_user_not_found(self):
"""测试更新不存在的用户返回 404。"""
response = client.put(
"/api/users/user-999",
json={"username": "new_name"},
)
assert response.status_code == 404
def test_update_username_conflict(self):
"""测试更新为已存在的用户名返回 409。"""
response = client.put(
"/api/users/user-001",
json={"username": "bob"},
)
assert response.status_code == 409
# ──────────────────────────────────────────────
# 用户删除测试
# ──────────────────────────────────────────────
class TestDeleteUser:
"""用户删除接口测试类。"""
def test_delete_user_success(self):
"""测试成功删除用户。"""
response = client.delete("/api/users/user-001")
assert response.status_code == 200
data = response.json()
assert "成功删除" in data["message"]
# 验证用户确实被删除
get_response = client.get("/api/users/user-001")
assert get_response.status_code == 404
def test_delete_user_not_found(self):
"""测试删除不存在的用户返回 404。"""
response = client.delete("/api/users/user-999")
assert response.status_code == 404
# ──────────────────────────────────────────────
# 用户登录测试
# ──────────────────────────────────────────────
class TestLogin:
"""用户登录接口测试类。"""
def test_login_success(self):
"""测试使用正确的用户名和密码登录成功。"""
response = client.post(
"/api/users/login",
json={"username": "alice", "password": "abc123"},
)
assert response.status_code == 200
data = response.json()
assert data["username"] == "alice"
def test_login_wrong_password(self):
"""测试使用错误密码登录返回 401。"""
response = client.post(
"/api/users/login",
json={"username": "alice", "password": "wrong_password"},
)
assert response.status_code == 401
def test_login_user_not_found(self):
"""测试使用不存在的用户名登录返回 401。"""
response = client.post(
"/api/users/login",
json={"username": "nonexistent", "password": "password123"},
)
assert response.status_code == 401