|
|
from django.test import Client, RequestFactory, TestCase
|
|
|
from django.urls import reverse
|
|
|
from django.utils import timezone
|
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
|
|
from accounts.models import BlogUser
|
|
|
from blog.models import Article, Category
|
|
|
from djangoblog.utils import *
|
|
|
from . import utils
|
|
|
|
|
|
|
|
|
# Create your tests here.
|
|
|
|
|
|
class AccountTest(TestCase):
|
|
|
"""
|
|
|
账户功能测试套件
|
|
|
测试用户注册、登录、密码重置等核心功能的正确性
|
|
|
继承Django的TestCase,提供数据库事务支持和断言方法
|
|
|
"""
|
|
|
|
|
|
def setUp(self):
|
|
|
"""
|
|
|
测试前置设置方法
|
|
|
在每个测试方法执行前运行,用于准备测试数据
|
|
|
避免测试间的数据污染,确保测试独立性
|
|
|
"""
|
|
|
self.client = Client() #ZXY: Django测试客户端,用于模拟HTTP请求
|
|
|
self.factory = RequestFactory() #ZXY: 请求工厂,用于创建请求对象进行视图测试
|
|
|
#ZXY: 创建测试用户 - 使用create_user方法创建普通用户
|
|
|
self.blog_user = BlogUser.objects.create_user(
|
|
|
username="test",
|
|
|
email="admin@admin.com",
|
|
|
password="12345678" #ZXY: 测试密码,实际项目中应使用更强密码
|
|
|
)
|
|
|
self.new_test = "xxx123--=" #ZXY: 测试用的新密码
|
|
|
|
|
|
def test_validate_account(self):
|
|
|
"""
|
|
|
测试账户验证功能
|
|
|
验证超级用户创建、登录权限和管理后台访问
|
|
|
这是一个综合性测试,覆盖用户生命周期多个环节
|
|
|
"""
|
|
|
site = get_current_site().domain #ZXY: 获取当前站点域名
|
|
|
#ZXY: 创建超级用户 - 测试管理员账户创建功能
|
|
|
user = BlogUser.objects.create_superuser(
|
|
|
email="liangliangyy1@gmail.com",
|
|
|
username="liangliangyy1",
|
|
|
password="qwer!@#$ggg") #ZXY: 复杂密码测试
|
|
|
testuser = BlogUser.objects.get(username='liangliangyy1') #ZXY: 从数据库检索用户验证创建成功
|
|
|
|
|
|
#ZXY: 测试登录功能 - 使用测试客户端模拟用户登录
|
|
|
loginresult = self.client.login(
|
|
|
username='liangliangyy1',
|
|
|
password='qwer!@#$ggg')
|
|
|
self.assertEqual(loginresult, True) #ZXY: 断言登录成功返回True
|
|
|
|
|
|
#ZXY: 测试管理后台访问权限 - 超级用户应该能访问/admin/
|
|
|
response = self.client.get('/admin/')
|
|
|
self.assertEqual(response.status_code, 200) #ZXY: 断言HTTP 200响应
|
|
|
|
|
|
#ZXY: 创建测试分类 - 为后续文章测试准备数据
|
|
|
category = Category()
|
|
|
category.name = "categoryaaa"
|
|
|
category.creation_time = timezone.now()
|
|
|
category.last_modify_time = timezone.now()
|
|
|
category.save()
|
|
|
|
|
|
#ZXY: 创建测试文章 - 验证用户与文章的关联关系
|
|
|
article = Article()
|
|
|
article.title = "nicetitleaaa"
|
|
|
article.body = "nicecontentaaa"
|
|
|
article.author = user #ZXY: 关联刚创建的超级用户
|
|
|
article.category = category
|
|
|
article.type = 'a' #ZXY: 文章类型
|
|
|
article.status = 'p' #ZXY: 发布状态
|
|
|
article.save()
|
|
|
|
|
|
#ZXY: 测试文章管理页面访问 - 验证用户对自有文章的编辑权限
|
|
|
response = self.client.get(article.get_admin_url())
|
|
|
self.assertEqual(response.status_code, 200) #ZXY: 断言可以正常访问文章管理页
|
|
|
|
|
|
def test_validate_register(self):
|
|
|
"""
|
|
|
测试用户注册完整流程
|
|
|
覆盖注册表单提交、邮箱验证、账户激活等关键步骤
|
|
|
验证新用户能否成功注册并正常使用系统
|
|
|
"""
|
|
|
#ZXY: 验证注册前用户不存在
|
|
|
self.assertEquals(
|
|
|
0, len(
|
|
|
BlogUser.objects.filter(
|
|
|
email='user123@user.com'))) #ZXY: 断言邮箱尚未注册
|
|
|
|
|
|
#ZXY: 提交注册表单 - 模拟用户注册请求
|
|
|
response = self.client.post(reverse('account:register'), {
|
|
|
'username': 'user1233',
|
|
|
'email': 'user123@user.com',
|
|
|
'password1': 'password123!q@wE#R$T', #ZXY: 强密码测试
|
|
|
'password2': 'password123!q@wE#R$T', #ZXY: 确认密码
|
|
|
})
|
|
|
|
|
|
#ZXY: 验证用户创建成功
|
|
|
self.assertEquals(
|
|
|
1, len(
|
|
|
BlogUser.objects.filter(
|
|
|
email='user123@user.com'))) #ZXY: 断言用户已创建
|
|
|
user = BlogUser.objects.filter(email='user123@user.com')[0] #ZXY: 获取新创建的用户
|
|
|
|
|
|
#ZXY: 生成邮箱验证签名 - 测试安全验证机制
|
|
|
sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id)))
|
|
|
path = reverse('accounts:result')
|
|
|
url = '{path}?type=validation&id={id}&sign={sign}'.format(
|
|
|
path=path, id=user.id, sign=sign) #ZXY: 构建验证URL
|
|
|
|
|
|
#ZXY: 测试邮箱验证页面访问
|
|
|
response = self.client.get(url)
|
|
|
self.assertEqual(response.status_code, 200) #ZXY: 断言验证页面可访问
|
|
|
|
|
|
#ZXY: 测试新用户登录功能
|
|
|
self.client.login(username='user1233', password='password123!q@wE#R$T')
|
|
|
user = BlogUser.objects.filter(email='user123@user.com')[0]
|
|
|
|
|
|
#ZXY: 提升用户权限进行进一步测试
|
|
|
user.is_superuser = True
|
|
|
user.is_staff = True
|
|
|
user.save()
|
|
|
delete_sidebar_cache() #ZXY: 清理缓存
|
|
|
|
|
|
#ZXY: 创建测试数据验证完整功能流程
|
|
|
category = Category()
|
|
|
category.name = "categoryaaa"
|
|
|
category.creation_time = timezone.now()
|
|
|
category.last_modify_time = timezone.now()
|
|
|
category.save()
|
|
|
|
|
|
article = Article()
|
|
|
article.category = category
|
|
|
article.title = "nicetitle333"
|
|
|
article.body = "nicecontentttt"
|
|
|
article.author = user
|
|
|
|
|
|
article.type = 'a'
|
|
|
article.status = 'p'
|
|
|
article.save()
|
|
|
|
|
|
#ZXY: 测试文章管理权限
|
|
|
response = self.client.get(article.get_admin_url())
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
#ZXY: 测试退出登录功能
|
|
|
response = self.client.get(reverse('account:logout'))
|
|
|
self.assertIn(response.status_code, [301, 302, 200]) #ZXY: 退出可能重定向
|
|
|
|
|
|
#ZXY: 验证退出后权限失效
|
|
|
response = self.client.get(article.get_admin_url())
|
|
|
self.assertIn(response.status_code, [301, 302, 200]) #ZXY: 应该无法直接访问
|
|
|
|
|
|
#ZXY: 测试重新登录
|
|
|
response = self.client.post(reverse('account:login'), {
|
|
|
'username': 'user1233',
|
|
|
'password': 'password123'
|
|
|
})
|
|
|
self.assertIn(response.status_code, [301, 302, 200])
|
|
|
|
|
|
#ZXY: 验证重新登录后的权限恢复
|
|
|
response = self.client.get(article.get_admin_url())
|
|
|
self.assertIn(response.status_code, [301, 302, 200])
|
|
|
|
|
|
def test_verify_email_code(self):
|
|
|
"""
|
|
|
测试邮箱验证码功能
|
|
|
验证验证码的生成、发送、存储和验证全流程
|
|
|
这是密码重置功能的核心安全机制测试
|
|
|
"""
|
|
|
to_email = "admin@admin.com"
|
|
|
code = generate_code() #ZXY: 生成随机验证码
|
|
|
|
|
|
#ZXY: 测试验证码存储功能
|
|
|
utils.set_code(to_email, code)
|
|
|
#ZXY: 测试邮件发送功能 - 在实际环境中会真正发送邮件
|
|
|
utils.send_verify_email(to_email, code)
|
|
|
|
|
|
#ZXY: 测试正确验证码验证
|
|
|
err = utils.verify("admin@admin.com", code)
|
|
|
self.assertEqual(err, None) #ZXY: 断言验证成功,返回None
|
|
|
|
|
|
#ZXY: 测试错误验证码验证
|
|
|
err = utils.verify("admin@123.com", code)
|
|
|
self.assertEqual(type(err), str) #ZXY: 断言验证失败返回错误信息字符串
|
|
|
|
|
|
def test_forget_password_email_code_success(self):
|
|
|
"""
|
|
|
测试忘记密码验证码请求 - 成功场景
|
|
|
验证系统能正确处理合法的密码重置请求
|
|
|
"""
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password_code"),
|
|
|
data=dict(email="admin@admin.com") #ZXY: 使用已注册的邮箱
|
|
|
)
|
|
|
|
|
|
self.assertEqual(resp.status_code, 200) #ZXY: 断言请求成功
|
|
|
self.assertEqual(resp.content.decode("utf-8"), "ok") #ZXY: 断言返回正确消息
|
|
|
|
|
|
def test_forget_password_email_code_fail(self):
|
|
|
"""
|
|
|
测试忘记密码验证码请求 - 失败场景
|
|
|
验证系统能正确处理各种异常输入情况
|
|
|
"""
|
|
|
#ZXY: 测试空数据提交
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password_code"),
|
|
|
data=dict() #ZXY: 空数据
|
|
|
)
|
|
|
self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱") #ZXY: 断言错误处理
|
|
|
|
|
|
#ZXY: 测试无效邮箱格式
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password_code"),
|
|
|
data=dict(email="admin@com") #ZXY: 无效邮箱格式
|
|
|
)
|
|
|
self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱") #ZXY: 断言格式验证
|
|
|
|
|
|
def test_forget_password_email_success(self):
|
|
|
"""
|
|
|
测试完整密码重置流程 - 成功场景
|
|
|
验证用户能通过验证码成功重置密码
|
|
|
"""
|
|
|
code = generate_code()
|
|
|
utils.set_code(self.blog_user.email, code) #ZXY: 存储验证码
|
|
|
data = dict(
|
|
|
new_password1=self.new_test,
|
|
|
new_password2=self.new_test,
|
|
|
email=self.blog_user.email,
|
|
|
code=code, #ZXY: 正确的验证码
|
|
|
)
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password"),
|
|
|
data=data
|
|
|
)
|
|
|
self.assertEqual(resp.status_code, 302) #ZXY: 断言重定向响应
|
|
|
|
|
|
#ZXY: 验证用户密码是否修改成功 - 从数据库重新获取用户验证密码变更
|
|
|
blog_user = BlogUser.objects.filter(
|
|
|
email=self.blog_user.email,
|
|
|
).first() # type: BlogUser
|
|
|
self.assertNotEqual(blog_user, None) #ZXY: 断言用户存在
|
|
|
self.assertEqual(blog_user.check_password(data["new_password1"]), True) #ZXY: 断言密码验证通过
|
|
|
|
|
|
def test_forget_password_email_not_user(self):
|
|
|
"""
|
|
|
测试密码重置 - 用户不存在场景
|
|
|
验证系统对未注册邮箱的处理
|
|
|
"""
|
|
|
data = dict(
|
|
|
new_password1=self.new_test,
|
|
|
new_password2=self.new_test,
|
|
|
email="123@123.com", #ZXY: 未注册的邮箱
|
|
|
code="123456",
|
|
|
)
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password"),
|
|
|
data=data
|
|
|
)
|
|
|
|
|
|
self.assertEqual(resp.status_code, 200) #ZXY: 断言停留在原页面(表单验证失败)
|
|
|
|
|
|
|
|
|
def test_forget_password_email_code_error(self):
|
|
|
"""
|
|
|
测试密码重置 - 验证码错误场景
|
|
|
验证系统对错误验证码的拒绝处理
|
|
|
"""
|
|
|
code = generate_code()
|
|
|
utils.set_code(self.blog_user.email, code) #ZXY: 存储正确验证码
|
|
|
data = dict(
|
|
|
new_password1=self.new_test,
|
|
|
new_password2=self.new_test,
|
|
|
email=self.blog_user.email,
|
|
|
code="111111", #ZXY: 错误的验证码
|
|
|
)
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password"),
|
|
|
data=data
|
|
|
)
|
|
|
|
|
|
self.assertEqual(resp.status_code, 200) #ZXY: 断言表单验证失败,停留在原页面
|
|
|
|