# 导入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)