Update tests.py

pull/8/head
pig6z2klp 5 months ago
parent 34edc2603e
commit 3fdb2da6ca

@ -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
Loading…
Cancel
Save