jiachenlong/backend/tests/test_auth.py

239 lines
8.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# tests/test_auth.py - 认证模块单元测试
import pytest
from app.core.auth import (
verify_password,
get_password_hash,
create_access_token,
decode_access_token,
)
class TestPasswordHashing:
"""密码哈希与验证测试"""
def test_hash_password_returns_string(self):
"""哈希密码应返回字符串"""
password = "testpassword123"
hashed = get_password_hash(password)
assert isinstance(hashed, str)
assert hashed != password
def test_hash_password_different_each_time(self):
"""每次哈希应不同bcrypt使用随机盐"""
password = "testpassword123"
hash1 = get_password_hash(password)
hash2 = get_password_hash(password)
assert hash1 != hash2
def test_verify_password_correct(self):
"""正确密码应验证通过"""
password = "testpassword123"
hashed = get_password_hash(password)
assert verify_password(password, hashed) is True
def test_verify_password_incorrect(self):
"""错误密码应验证失败"""
password = "testpassword123"
wrong_password = "wrongpassword456"
hashed = get_password_hash(password)
assert verify_password(wrong_password, hashed) is False
def test_verify_password_empty(self):
"""空密码应验证失败"""
password = "testpassword123"
hashed = get_password_hash(password)
assert verify_password("", hashed) is False
def test_verify_password_none(self):
"""None密码应验证失败"""
password = "testpassword123"
hashed = get_password_hash(password)
assert verify_password(None, hashed) is False
class TestJWTToken:
"""JWT令牌创建与解析测试"""
def test_create_and_decode_token(self):
"""创建令牌后能正确解码"""
data = {"sub": "user123", "role": "admin"}
token = create_access_token(data)
assert isinstance(token, str)
assert len(token) > 0
payload = decode_access_token(token)
assert payload is not None
assert payload["sub"] == "user123"
assert payload["role"] == "admin"
def test_decode_invalid_token_returns_none(self):
"""无效令牌应返回None"""
invalid_token = "invalid.token.here"
payload = decode_access_token(invalid_token)
assert payload is None
def test_decode_empty_token_returns_none(self):
"""空令牌应返回None"""
payload = decode_access_token("")
assert payload is None
def test_token_contains_expiration(self):
"""令牌应包含过期时间"""
data = {"sub": "user123"}
token = create_access_token(data)
payload = decode_access_token(token)
assert "exp" in payload
class TestAuthEndpoints:
"""认证API端点测试"""
def test_register_success(self, client, sample_user_data):
"""用户注册成功"""
response = client.post("/api/auth/register", json=sample_user_data)
assert response.status_code == 200
data = response.json()
assert data["username"] == sample_user_data["f01_01_name"]
assert "id" in data
assert "user_code" in data
def test_register_duplicate_username(self, client, sample_user_data, registered_user):
"""重复用户名应注册失败"""
response = client.post("/api/auth/register", json=sample_user_data)
assert response.status_code == 400
assert "已存在" in response.json().get("detail", "")
def test_register_short_password(self, client, sample_user_data):
"""密码过短应注册失败"""
sample_user_data["password"] = "123" # 小于6位
response = client.post("/api/auth/register", json=sample_user_data)
assert response.status_code == 422 # Pydantic验证失败
def test_login_success(self, client, sample_user_data):
"""登录成功返回token"""
# 先注册
client.post("/api/auth/register", json=sample_user_data)
# 再登录
response = client.post(
"/api/auth/login",
data={
"username": sample_user_data["f01_01_name"],
"password": sample_user_data["password"],
},
)
assert response.status_code == 200
data = response.json()
assert "access_token" in data
assert data["token_type"] == "bearer"
def test_login_with_user_code(self, client, sample_user_data):
"""使用用户编码登录"""
# 先注册
client.post("/api/auth/register", json=sample_user_data)
# 获取用户编码
user_response = client.post("/api/auth/register", json=sample_user_data)
registered_user_response = client.post(
"/api/auth/login",
data={
"username": sample_user_data["f01_01_name"],
"password": sample_user_data["password"],
},
)
token = registered_user_response.json()["access_token"]
me_response = client.get("/api/auth/me", headers={"Authorization": f"Bearer {token}"})
user_code = me_response.json()["user_code"]
# 用用户编码登录
login_response = client.post(
"/api/auth/login",
data={
"username": user_code,
"password": sample_user_data["password"],
},
)
assert login_response.status_code == 200
assert "access_token" in login_response.json()
def test_login_wrong_password(self, client, sample_user_data):
"""错误密码应登录失败"""
# 先注册
client.post("/api/auth/register", json=sample_user_data)
response = client.post(
"/api/auth/login",
data={
"username": sample_user_data["f01_01_name"],
"password": "wrongpassword",
},
)
assert response.status_code == 401
def test_login_nonexistent_user(self, client):
"""不存在的用户应登录失败"""
response = client.post(
"/api/auth/login",
data={
"username": "nonexistent",
"password": "somepassword",
},
)
assert response.status_code == 401
def test_get_current_user_success(self, client, auth_headers):
"""获取当前用户信息成功"""
response = client.get("/api/auth/me", headers=auth_headers)
assert response.status_code == 200
data = response.json()
assert "username" in data
assert "user_code" in data
def test_get_current_user_no_token(self, client):
"""无令牌应返回401"""
response = client.get("/api/auth/me")
assert response.status_code == 401
def test_get_current_user_invalid_token(self, client):
"""无效令牌应返回401"""
response = client.get(
"/api/auth/me",
headers={"Authorization": "Bearer invalid-token"},
)
assert response.status_code == 401
def test_change_password_success(self, client, auth_headers, sample_user_data):
"""修改密码成功"""
response = client.post(
"/api/auth/change-password",
headers=auth_headers,
json={
"old_password": sample_user_data["password"],
"new_password": "newpassword456",
},
)
assert response.status_code == 200
# 用新密码登录应该成功
login_response = client.post(
"/api/auth/login",
data={
"username": sample_user_data["f01_01_name"],
"password": "newpassword456",
},
)
assert login_response.status_code == 200
def test_change_password_wrong_old_password(self, client, auth_headers, sample_user_data):
"""旧密码错误应修改失败"""
response = client.post(
"/api/auth/change-password",
headers=auth_headers,
json={
"old_password": "wrongoldpassword",
"new_password": "newpassword456",
},
)
assert response.status_code == 400