From 3fdb2da6ca1b73518fb243ca2e652463a0ca4df9 Mon Sep 17 00:00:00 2001 From: pig6z2klp <431960330@qq.com> Date: Tue, 14 Oct 2025 11:58:13 +0800 Subject: [PATCH] Update tests.py --- src/DjangoBlog-master/oauth/tests.py | 197 ++++++++++++++++++--------- 1 file changed, 130 insertions(+), 67 deletions(-) diff --git a/src/DjangoBlog-master/oauth/tests.py b/src/DjangoBlog-master/oauth/tests.py index bb23b9b..3f86a87 100644 --- a/src/DjangoBlog-master/oauth/tests.py +++ b/src/DjangoBlog-master/oauth/tests.py @@ -1,129 +1,171 @@ import json -from unittest.mock import patch +from unittest.mock import patch # 用于用于模拟函数/方法的返回值,隔离外部依赖 from django.conf import settings -from django.contrib import auth -from django.test import Client, RequestFactory, TestCase -from django.urls import reverse +from django.contrib import auth # 用于用户认证相关操作 +from django.test import Client, RequestFactory, TestCase # Django测试工具 +from django.urls import reverse # 用于反向解析URL -from djangoblog.utils import get_sha256 -from oauth.models import OAuthConfig -from oauth.oauthmanager import BaseOauthManager +from djangoblog.utils import get_sha256 # 导入SHA256加密工具函数 +from oauth.models import OAuthConfig # 导入OAuth配置模型 +from oauth.oauthmanager import BaseOauthManager # 导入OAuth管理器基类 -# Create your tests here. +# 测试用例:测试OAuth配置及基础登录流程 class OAuthConfigTest(TestCase): def setUp(self): + # 初始化测试客户端(模拟用户请求)和请求工厂(构建请求对象) self.client = Client() self.factory = RequestFactory() def test_oauth_login_test(self): + # 创建一条微博OAuth配置记录 c = OAuthConfig() - c.type = 'weibo' - c.appkey = 'appkey' - c.appsecret = 'appsecret' - c.save() + c.type = 'weibo' # 平台类型为微博 + c.appkey = 'appkey' # 模拟AppKey + c.appsecret = 'appsecret' # 模拟AppSecret + c.save() # 保存到数据库 + # 测试访问微博OAuth登录URL是否正常跳转 response = self.client.get('/oauth/oauthlogin?type=weibo') - self.assertEqual(response.status_code, 302) - self.assertTrue("api.weibo.com" in response.url) + self.assertEqual(response.status_code, 302) # 期望302重定向 + self.assertTrue("api.weibo.com" in response.url) # 重定向地址应包含微博API域名 + # 测试授权回调处理是否正常 response = self.client.get('/oauth/authorize?type=weibo&code=code') - self.assertEqual(response.status_code, 302) - self.assertEqual(response.url, '/') + self.assertEqual(response.status_code, 302) # 期望302重定向 + self.assertEqual(response.url, '/') # 回调后默认跳转首页 +# 测试用例:测试各平台OAuth登录流程(微博、谷歌、GitHub、Facebook、QQ) class OauthLoginTest(TestCase): def setUp(self) -> None: + # 初始化测试客户端和请求工厂 self.client = Client() self.factory = RequestFactory() + # 初始化所有平台的OAuth配置 self.apps = self.init_apps() def init_apps(self): + # 获取所有OAuth管理器子类(各平台实现)并创建对应配置 applications = [p() for p in BaseOauthManager.__subclasses__()] for application in applications: c = OAuthConfig() - c.type = application.ICON_NAME.lower() - c.appkey = 'appkey' - c.appsecret = 'appsecret' - c.save() + c.type = application.ICON_NAME.lower() # 平台类型与管理器图标名一致 + c.appkey = 'appkey' # 统一模拟AppKey + c.appsecret = 'appsecret' # 统一模拟AppSecret + c.save() # 保存配置 return applications def get_app_by_type(self, type): + # 根据平台类型获取对应的OAuth管理器实例 for app in self.apps: if app.ICON_NAME.lower() == type: return app - @patch("oauth.oauthmanager.WBOauthManager.do_post") - @patch("oauth.oauthmanager.WBOauthManager.do_get") + # 测试微博登录流程(使用mock模拟HTTP请求返回值) + @patch("oauth.oauthmanager.WBOauthManager.do_post") # 模拟POST请求 + @patch("oauth.oauthmanager.WBOauthManager.do_get") # 模拟GET请求 def test_weibo_login(self, mock_do_get, mock_do_post): + # 获取微博管理器实例 weibo_app = self.get_app_by_type('weibo') - assert weibo_app + assert weibo_app # 确保实例存在 + + # 生成授权URL(测试URL生成逻辑) url = weibo_app.get_authorization_url() - mock_do_post.return_value = json.dumps({"access_token": "access_token", - "uid": "uid" - }) + + # 模拟获取token的响应(返回access_token和uid) + mock_do_post.return_value = json.dumps({ + "access_token": "access_token", + "uid": "uid" + }) + # 模拟获取用户信息的响应 mock_do_get.return_value = json.dumps({ - "avatar_large": "avatar_large", - "screen_name": "screen_name", - "id": "id", - "email": "email", + "avatar_large": "avatar_large", # 头像URL + "screen_name": "screen_name", # 昵称 + "id": "id", # 用户ID + "email": "email", # 邮箱 }) + + # 测试通过code获取用户信息的流程 userinfo = weibo_app.get_access_token_by_code('code') - self.assertEqual(userinfo.token, 'access_token') - self.assertEqual(userinfo.openid, 'id') + # 验证返回的用户信息是否正确 + self.assertEqual(userinfo.token, 'access_token') # token匹配 + self.assertEqual(userinfo.openid, 'id') # openid匹配 + # 测试谷歌登录流程 @patch("oauth.oauthmanager.GoogleOauthManager.do_post") @patch("oauth.oauthmanager.GoogleOauthManager.do_get") def test_google_login(self, mock_do_get, mock_do_post): google_app = self.get_app_by_type('google') assert google_app + + # 生成授权URL url = google_app.get_authorization_url() + + # 模拟获取token的响应 mock_do_post.return_value = json.dumps({ "access_token": "access_token", - "id_token": "id_token", + "id_token": "id_token" # 谷歌用id_token作为openid }) + # 模拟获取用户信息的响应 mock_do_get.return_value = json.dumps({ - "picture": "picture", - "name": "name", - "sub": "sub", - "email": "email", + "picture": "picture", # 头像 + "name": "name", # 姓名 + "sub": "sub", # 唯一标识 + "email": "email" # 邮箱 }) + + # 测试获取token和用户信息 token = google_app.get_access_token_by_code('code') userinfo = google_app.get_oauth_userinfo() self.assertEqual(userinfo.token, 'access_token') self.assertEqual(userinfo.openid, 'sub') + # 测试GitHub登录流程 @patch("oauth.oauthmanager.GitHubOauthManager.do_post") @patch("oauth.oauthmanager.GitHubOauthManager.do_get") def test_github_login(self, mock_do_get, mock_do_post): github_app = self.get_app_by_type('github') assert github_app + + # 生成授权URL并验证包含GitHub域名和client_id url = github_app.get_authorization_url() self.assertTrue("github.com" in url) self.assertTrue("client_id" in url) + + # 模拟GitHub返回的token(表单格式) mock_do_post.return_value = "access_token=gho_16C7e42F292c6912E7710c838347Ae178B4a&scope=repo%2Cgist&token_type=bearer" + # 模拟用户信息响应 mock_do_get.return_value = json.dumps({ - "avatar_url": "avatar_url", - "name": "name", - "id": "id", - "email": "email", + "avatar_url": "avatar_url", # 头像 + "name": "name", # 姓名 + "id": "id", # 唯一ID + "email": "email" # 邮箱 }) + + # 测试获取token和用户信息 token = github_app.get_access_token_by_code('code') userinfo = github_app.get_oauth_userinfo() self.assertEqual(userinfo.token, 'gho_16C7e42F292c6912E7710c838347Ae178B4a') self.assertEqual(userinfo.openid, 'id') + # 测试Facebook登录流程 @patch("oauth.oauthmanager.FaceBookOauthManager.do_post") @patch("oauth.oauthmanager.FaceBookOauthManager.do_get") def test_facebook_login(self, mock_do_get, mock_do_post): facebook_app = self.get_app_by_type('facebook') assert facebook_app + + # 生成授权URL并验证包含Facebook域名 url = facebook_app.get_authorization_url() self.assertTrue("facebook.com" in url) + + # 模拟获取token的响应 mock_do_post.return_value = json.dumps({ - "access_token": "access_token", + "access_token": "access_token" }) + # 模拟用户信息响应(头像为嵌套结构) mock_do_get.return_value = json.dumps({ "name": "name", "id": "id", @@ -134,14 +176,18 @@ class OauthLoginTest(TestCase): } } }) + + # 测试获取token和用户信息 token = facebook_app.get_access_token_by_code('code') userinfo = facebook_app.get_oauth_userinfo() self.assertEqual(userinfo.token, 'access_token') + # 测试QQ登录流程(QQ需额外获取openid) @patch("oauth.oauthmanager.QQOauthManager.do_get", side_effect=[ - 'access_token=access_token&expires_in=3600', - 'callback({"client_id":"appid","openid":"openid"} );', - json.dumps({ + # 模拟三次GET请求的返回值(按调用顺序) + 'access_token=access_token&expires_in=3600', # 获取token的响应(表单格式) + 'callback({"client_id":"appid","openid":"openid"} );', # 获取openid的响应 + json.dumps({ # 获取用户信息的响应 "nickname": "nickname", "email": "email", "figureurl": "figureurl", @@ -151,19 +197,26 @@ class OauthLoginTest(TestCase): def test_qq_login(self, mock_do_get): qq_app = self.get_app_by_type('qq') assert qq_app + + # 生成授权URL并验证包含QQ域名 url = qq_app.get_authorization_url() self.assertTrue("qq.com" in url) + + # 测试获取token和用户信息 token = qq_app.get_access_token_by_code('code') userinfo = qq_app.get_oauth_userinfo() self.assertEqual(userinfo.token, 'access_token') + # 测试微博登录(包含邮箱,可直接绑定用户) @patch("oauth.oauthmanager.WBOauthManager.do_post") @patch("oauth.oauthmanager.WBOauthManager.do_get") def test_weibo_authoriz_login_with_email(self, mock_do_get, mock_do_post): - - mock_do_post.return_value = json.dumps({"access_token": "access_token", - "uid": "uid" - }) + # 模拟获取token的响应 + mock_do_post.return_value = json.dumps({ + "access_token": "access_token", + "uid": "uid" + }) + # 模拟包含邮箱的用户信息 mock_user_info = { "avatar_large": "avatar_large", "screen_name": "screen_name1", @@ -172,38 +225,46 @@ class OauthLoginTest(TestCase): } mock_do_get.return_value = json.dumps(mock_user_info) + # 测试访问登录URL是否重定向到微博 response = self.client.get('/oauth/oauthlogin?type=weibo') self.assertEqual(response.status_code, 302) self.assertTrue("api.weibo.com" in response.url) + # 测试授权回调后是否跳转首页 response = self.client.get('/oauth/authorize?type=weibo&code=code') self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/') + # 验证用户已登录且信息正确 user = auth.get_user(self.client) assert user.is_authenticated self.assertTrue(user.is_authenticated) self.assertEqual(user.username, mock_user_info['screen_name']) self.assertEqual(user.email, mock_user_info['email']) - self.client.logout() + # 测试登出后再次登录是否正常 + self.client.logout() response = self.client.get('/oauth/authorize?type=weibo&code=code') self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/') + # 再次验证用户登录状态 user = auth.get_user(self.client) assert user.is_authenticated self.assertTrue(user.is_authenticated) self.assertEqual(user.username, mock_user_info['screen_name']) self.assertEqual(user.email, mock_user_info['email']) + # 测试微博登录(无邮箱,需补充邮箱并绑定) @patch("oauth.oauthmanager.WBOauthManager.do_post") @patch("oauth.oauthmanager.WBOauthManager.do_get") def test_weibo_authoriz_login_without_email(self, mock_do_get, mock_do_post): - - mock_do_post.return_value = json.dumps({"access_token": "access_token", - "uid": "uid" - }) + # 模拟获取token的响应 + mock_do_post.return_value = json.dumps({ + "access_token": "access_token", + "uid": "uid" + }) + # 模拟不含邮箱的用户信息 mock_user_info = { "avatar_large": "avatar_large", "screen_name": "screen_name1", @@ -211,39 +272,41 @@ class OauthLoginTest(TestCase): } mock_do_get.return_value = json.dumps(mock_user_info) + # 测试访问登录URL response = self.client.get('/oauth/oauthlogin?type=weibo') self.assertEqual(response.status_code, 302) self.assertTrue("api.weibo.com" in response.url) + # 测试授权回调后是否跳转邮箱补充页面 response = self.client.get('/oauth/authorize?type=weibo&code=code') - self.assertEqual(response.status_code, 302) + # 提取OAuth用户ID(从跳转URL中解析) oauth_user_id = int(response.url.split('/')[-1].split('.')[0]) self.assertEqual(response.url, f'/oauth/requireemail/{oauth_user_id}.html') + # 测试提交邮箱表单 response = self.client.post(response.url, {'email': 'test@gmail.com', 'oauthid': oauth_user_id}) - self.assertEqual(response.status_code, 302) - sign = get_sha256(settings.SECRET_KEY + - str(oauth_user_id) + settings.SECRET_KEY) - url = reverse('oauth:bindsuccess', kwargs={ - 'oauthid': oauth_user_id, - }) + # 生成验证签名(用于邮箱验证) + sign = get_sha256(settings.SECRET_KEY + str(oauth_user_id) + settings.SECRET_KEY) + + # 验证跳转URL是否正确(绑定成功页) + url = reverse('oauth:bindsuccess', kwargs={'oauthid': oauth_user_id}) self.assertEqual(response.url, f'{url}?type=email') - path = reverse('oauth:email_confirm', kwargs={ - 'id': oauth_user_id, - 'sign': sign - }) + # 测试邮箱验证链接 + path = reverse('oauth:email_confirm', kwargs={'id': oauth_user_id, 'sign': sign}) response = self.client.get(path) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, f'/oauth/bindsuccess/{oauth_user_id}.html?type=success') + + # 验证用户已绑定且信息正确 user = auth.get_user(self.client) from oauth.models import OAuthUser oauth_user = OAuthUser.objects.get(author=user) self.assertTrue(user.is_authenticated) self.assertEqual(user.username, mock_user_info['screen_name']) - self.assertEqual(user.email, 'test@gmail.com') - self.assertEqual(oauth_user.pk, oauth_user_id) + self.assertEqual(user.email, 'test@gmail.com') # 验证补充的邮箱 + self.assertEqual(oauth_user.pk, oauth_user_id) # 验证关联的OAuth用户ID \ No newline at end of file