|
|
# 导入Django测试所需的核心类:Client模拟HTTP请求、RequestFactory创建请求对象、TestCase测试基类
|
|
|
from django.test import Client, RequestFactory, TestCase
|
|
|
# 导入reverse通过URL名称生成路径,用于测试中定位接口
|
|
|
from django.urls import reverse
|
|
|
# 导入timezone处理时间相关字段,用于创建测试数据
|
|
|
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
|
|
|
|
|
|
|
|
|
# 定义账户相关测试类,继承Django的TestCase(提供测试框架支持)
|
|
|
class AccountTest(TestCase):
|
|
|
def setUp(self):
|
|
|
"""
|
|
|
测试初始化方法,在每个测试方法执行前自动调用
|
|
|
用于创建共用的测试对象,避免代码重复
|
|
|
"""
|
|
|
# 创建测试客户端,用于模拟用户发送HTTP请求
|
|
|
self.client = Client()
|
|
|
# 创建请求工厂,用于生成原始请求对象(按需使用)
|
|
|
self.factory = RequestFactory()
|
|
|
# 创建普通测试用户,用户名test、邮箱admin@admin.com、密码12345678
|
|
|
self.blog_user = BlogUser.objects.create_user(
|
|
|
username="test",
|
|
|
email="admin@admin.com",
|
|
|
password="12345678"
|
|
|
)
|
|
|
# 定义测试用的新密码,后续忘记密码测试中使用
|
|
|
self.new_test = "xxx123--="
|
|
|
|
|
|
def test_validate_account(self):
|
|
|
"""测试账户基础功能:超级用户创建、登录验证、admin访问、内容创建与管理"""
|
|
|
# 获取当前站点域名(测试中未实际使用,保持原逻辑)
|
|
|
site = get_current_site().domain
|
|
|
# 创建超级用户(拥有admin管理权限)
|
|
|
user = BlogUser.objects.create_superuser(
|
|
|
email="liangliangyy1@gmail.com",
|
|
|
username="liangliangyy1",
|
|
|
password="qwer!@#$ggg")
|
|
|
# 通过用户名查询刚创建的超级用户,验证创建成功
|
|
|
testuser = BlogUser.objects.get(username='liangliangyy1')
|
|
|
|
|
|
# 使用测试客户端模拟超级用户登录
|
|
|
loginresult = self.client.login(
|
|
|
username='liangliangyy1',
|
|
|
password='qwer!@#$ggg')
|
|
|
# 断言登录成功(返回True)
|
|
|
self.assertEqual(loginresult, True)
|
|
|
# 模拟访问admin后台页面
|
|
|
response = self.client.get('/admin/')
|
|
|
# 断言admin页面访问成功(状态码200)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
# 创建测试分类:设置名称、创建时间、修改时间并保存
|
|
|
category = Category()
|
|
|
category.name = "categoryaaa"
|
|
|
category.creation_time = timezone.now()
|
|
|
category.last_modify_time = timezone.now()
|
|
|
category.save()
|
|
|
|
|
|
# 创建测试文章:关联作者(超级用户)和分类,设置标题、内容、类型、状态并保存
|
|
|
article = Article()
|
|
|
article.title = "nicetitleaaa"
|
|
|
article.body = "nicecontentaaa"
|
|
|
article.author = user
|
|
|
article.category = category
|
|
|
article.type = 'a' # 假设'a'代表普通文章类型
|
|
|
article.status = 'p' # 假设'p'代表已发布状态
|
|
|
article.save()
|
|
|
|
|
|
# 模拟访问文章的admin管理页面(通过文章模型的get_admin_url方法获取路径)
|
|
|
response = self.client.get(article.get_admin_url())
|
|
|
# 断言文章管理页面访问成功(状态码200)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
def test_validate_register(self):
|
|
|
"""测试用户注册流程:注册请求、注册后用户存在性、邮箱验证、登录与权限升级、内容管理"""
|
|
|
# 注册前断言:邮箱为user123@user.com的用户不存在(初始状态)
|
|
|
self.assertEquals(
|
|
|
0, len(
|
|
|
BlogUser.objects.filter(
|
|
|
email='user123@user.com')))
|
|
|
# 模拟发送注册请求:向account:register接口提交用户名、邮箱、两次一致的密码
|
|
|
response = self.client.post(reverse('account:register'), {
|
|
|
'username': 'user1233',
|
|
|
'email': 'user123@user.com',
|
|
|
'password1': 'password123!q@wE#R$T',
|
|
|
'password2': 'password123!q@wE#R$T',
|
|
|
})
|
|
|
# 注册后断言:邮箱为user123@user.com的用户存在(注册成功)
|
|
|
self.assertEquals(
|
|
|
1, len(
|
|
|
BlogUser.objects.filter(
|
|
|
email='user123@user.com')))
|
|
|
|
|
|
# 获取刚注册的用户,生成邮箱验证链接(使用项目加密逻辑生成签名)
|
|
|
user = BlogUser.objects.filter(email='user123@user.com')[0]
|
|
|
sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) # 双重SHA256加密签名
|
|
|
path = reverse('accounts:result') # 验证结果页的URL路径
|
|
|
url = '{path}?type=validation&id={id}&sign={sign}'.format(
|
|
|
path=path, id=user.id, sign=sign) # 拼接完整验证URL
|
|
|
# 模拟访问邮箱验证链接
|
|
|
response = self.client.get(url)
|
|
|
# 断言验证页面访问成功(状态码200)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
# 模拟刚注册的用户登录
|
|
|
self.client.login(username='user1233', password='password123!q@wE#R$T')
|
|
|
# 升级用户权限为超级用户(便于测试admin功能)
|
|
|
user = BlogUser.objects.filter(email='user123@user.com')[0]
|
|
|
user.is_superuser = True # 设为超级用户
|
|
|
user.is_staff = True # 允许登录admin
|
|
|
user.save()
|
|
|
# 删除侧边栏缓存(项目自定义缓存操作,测试中保持原逻辑)
|
|
|
delete_sidebar_cache()
|
|
|
|
|
|
# 创建测试分类(用于后续创建文章)
|
|
|
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()
|
|
|
|
|
|
# 模拟访问文章的admin管理页面
|
|
|
response = self.client.get(article.get_admin_url())
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
# 模拟用户登出
|
|
|
response = self.client.get(reverse('account:logout'))
|
|
|
# 断言登出请求响应正常(允许301/302重定向或200成功)
|
|
|
self.assertIn(response.status_code, [301, 302, 200])
|
|
|
|
|
|
# 登出后尝试访问文章admin页面(应被拒绝或重定向)
|
|
|
response = self.client.get(article.get_admin_url())
|
|
|
self.assertIn(response.status_code, [301, 302, 200])
|
|
|
|
|
|
# 模拟使用错误密码登录(密码不匹配)
|
|
|
response = self.client.post(reverse('account:login'), {
|
|
|
'username': 'user1233',
|
|
|
'password': 'password123'
|
|
|
})
|
|
|
# 断言登录请求响应正常(无论成功失败,状态码合法)
|
|
|
self.assertIn(response.status_code, [301, 302, 200])
|
|
|
|
|
|
# 错误登录后尝试访问文章admin页面(应被拒绝或重定向)
|
|
|
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() # 调用工具函数生成验证码
|
|
|
# 存储验证码(关联邮箱,用于后续验证)
|
|
|
utils.set_code(to_email, code)
|
|
|
# 发送验证邮件(测试中仅执行流程,不实际校验邮件发送结果)
|
|
|
utils.send_verify_email(to_email, code)
|
|
|
|
|
|
# 验证1:使用正确的邮箱和验证码,断言无错误返回(验证成功)
|
|
|
err = utils.verify("admin@admin.com", code)
|
|
|
self.assertEqual(err, None)
|
|
|
|
|
|
# 验证2:使用错误的邮箱(与存储的验证码不匹配),断言返回错误信息(字符串类型)
|
|
|
err = utils.verify("admin@123.com", code)
|
|
|
self.assertEqual(type(err), str)
|
|
|
|
|
|
def test_forget_password_email_code_success(self):
|
|
|
"""测试获取忘记密码验证码的成功场景:提交正确邮箱,返回成功响应"""
|
|
|
# 模拟向account:forget_password_code接口提交正确邮箱
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password_code"),
|
|
|
data=dict(email="admin@admin.com")
|
|
|
)
|
|
|
# 断言请求成功(状态码200)且返回内容为"ok"(表示验证码发送成功)
|
|
|
self.assertEqual(resp.status_code, 200)
|
|
|
self.assertEqual(resp.content.decode("utf-8"), "ok")
|
|
|
|
|
|
def test_forget_password_email_code_fail(self):
|
|
|
"""测试获取忘记密码验证码的失败场景:无邮箱、邮箱格式错误"""
|
|
|
# 失败场景1:不提交邮箱(空数据)
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password_code"),
|
|
|
data=dict()
|
|
|
)
|
|
|
# 断言返回"错误的邮箱"(参数缺失)
|
|
|
self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱")
|
|
|
|
|
|
# 失败场景2:提交格式错误的邮箱(admin@com不符合标准格式)
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password_code"),
|
|
|
data=dict(email="admin@com")
|
|
|
)
|
|
|
# 断言返回"错误的邮箱"(格式校验失败)
|
|
|
self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱")
|
|
|
|
|
|
def test_forget_password_email_success(self):
|
|
|
"""测试忘记密码重置成功场景:提交正确验证码和新密码,密码修改生效"""
|
|
|
# 生成验证码并关联测试用户的邮箱(模拟用户已获取验证码)
|
|
|
code = generate_code()
|
|
|
utils.set_code(self.blog_user.email, code)
|
|
|
# 构造忘记密码重置请求数据:新密码(两次一致)、用户邮箱、正确验证码
|
|
|
data = dict(
|
|
|
new_password1=self.new_test,
|
|
|
new_password2=self.new_test,
|
|
|
email=self.blog_user.email,
|
|
|
code=code,
|
|
|
)
|
|
|
# 模拟发送密码重置请求
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password"),
|
|
|
data=data
|
|
|
)
|
|
|
# 断言重置成功(重定向到结果页,状态码302)
|
|
|
self.assertEqual(resp.status_code, 302)
|
|
|
|
|
|
# 验证密码是否真的修改成功:查询用户并校验新密码
|
|
|
blog_user = BlogUser.objects.filter(
|
|
|
email=self.blog_user.email,
|
|
|
).first() # 获取用户实例
|
|
|
self.assertNotEqual(blog_user, None) # 断言用户存在
|
|
|
# 使用check_password方法验证新密码是否匹配(Django内置密码校验,自动处理哈希)
|
|
|
self.assertEqual(blog_user.check_password(data["new_password1"]), True)
|
|
|
|
|
|
def test_forget_password_email_not_user(self):
|
|
|
"""测试忘记密码重置失败场景:使用不存在的邮箱"""
|
|
|
# 构造请求数据:新密码、不存在的邮箱、任意验证码
|
|
|
data = dict(
|
|
|
new_password1=self.new_test,
|
|
|
new_password2=self.new_test,
|
|
|
email="123@123.com",
|
|
|
code="123456",
|
|
|
)
|
|
|
# 模拟发送密码重置请求
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password"),
|
|
|
data=data
|
|
|
)
|
|
|
# 断言请求响应正常(页面返回错误提示,状态码200)
|
|
|
self.assertEqual(resp.status_code, 200)
|
|
|
|
|
|
def test_forget_password_email_code_error(self):
|
|
|
"""测试忘记密码重置失败场景:验证码错误"""
|
|
|
# 生成正确验证码并关联用户邮箱,但请求时提交错误验证码
|
|
|
code = generate_code()
|
|
|
utils.set_code(self.blog_user.email, code)
|
|
|
data = dict(
|
|
|
new_password1=self.new_test,
|
|
|
new_password2=self.new_test,
|
|
|
email=self.blog_user.email,
|
|
|
code="111111", # 错误的验证码
|
|
|
)
|
|
|
# 模拟发送密码重置请求
|
|
|
resp = self.client.post(
|
|
|
path=reverse("account:forget_password"),
|
|
|
data=data
|
|
|
)
|
|
|
# 断言请求响应正常(页面返回验证码错误提示,状态码200)
|
|
|
self.assertEqual(resp.status_code, 200)
|