注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

网易杭州 QA Team

务实 专注 分享 做有态度的QA

 
 
 
 
 

日志

 
 

微信扫码登陆等SNS登陆的UI测试一种解决办法  

来自nowind   2016-12-14 15:54:26|  分类: 默认分类 |举报 |字号 订阅

  下载LOFTER 我的照片书  |
项目有微博,QQ,微信登陆,前两者登陆还可以通过传统的输入密码方式模拟,但是扫码就比较困难了。现在的第三方登陆基本采用OAuth2.0做认证,因此我们可以采用以下思路来解决问题:
1.假设一台可以实现部分oauth2.0 接口的服务器
2.在UI测试的服务器申请修改HOSTS,将需要Mock的服务器IP映射到Mock服务器上
3.Mock服务器按照一定的配置返回正确的(带有随机数据的)或者失败的(由于异常测试)
以微信的文档为例,http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
我们先看下OAuth2.0 协议,确定我们需要Mock的接口。按照协议要求,我们点击微信登陆后,会被重定向到一个微信域名的扫码页面,当用户完成扫码后,微信页面会跳转到一个我们服务器预先设定的回跳页面,并带了一个识别用户登陆信息的,后端服务器通过这个code向微信服务器请求获取access_token,并利用access_token获取用户的唯一标识,通过唯一标识判断用户身份。
我们需要mock的接口有 access_token和userinfo,这样我们足以应对通过uid来判断用户的登陆的Mock需求。
另外还有一个问题是OAuth服务器的认证服务器基本是https,不过我们的后端基本是会信任所有证书,所以我门在配置nginx时,需要一台支持https协议的。
我们先来看下基础的类:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import web,requests,yaml,sys,random,json,os

class OAuthMock:
def _getUidHash(self):
return hash(self._MockGetToken())%sys.maxsize
def isPost(self):
return web.ctx.method=='POST'
def init(self):
self.expires_in=3600*random.randint(1,4)
self.webIunpt=web.input()
def simpleBypass(self):
fullurl=web.ctx.homedomain+web.ctx.homepath+web.ctx.fullpath
try:
if self.isPost():
proxyResponse=requests.post(fullurl,web.data(),stream=True)
else:
proxyResponse=requests.get(fullurl,stream=True)
return proxyResponse.raw.read()
except:
pass
return ''
def _GetInputByOrder(self,orderlist):
for i in orderlist:
if i in self.webIunpt:
return self._earseEnds(self.webIunpt[i])
return None
def _earseEnds(self,method):
if method.endswith('_atoken') or method.endswith('_rtoken') or method.endswith('_openid'):
method=mothod[0:-7]
elif method.endswith('_uid'):
method=mothod[0:-4]
return method
def _MockGetToken(self):
return self._GetInputByOrder(['code','access_token','refresh_token','openid'])
def getSelfClassName(self):
return self.__class__.__name__
def verifyMethodInPattern(self,method,pattern):
methods=set(pattern.split(','))
method=self._earseEnds(method)
if '*' in methods:
return True
if method in methods:
return True
return False
def getResultForMethod(self,method):
method=method.split('.')[0]
try:
with open('oauth.yaml') as f:
authDataStore=yaml.load(f)
className=self.getSelfClassName()
if className in authDataStore: #第一层是类名
oauthMap=authDataStore[className]
token=self._MockGetToken()
if token in oauthMap:
if ('hook' in oauthMap[token]) and self.verifyMethodInPattern(method,oauthMap[token]['hook']) and (method in oauthMap[token]):
return oauthMap[token][method]
elif ('mock' in oauthMap[token]) and self.verifyMethodInPattern(method,oauthMap[token]['mock']):
return '__pass'
except Exception,e:
print e
pass
return None
def sendResult(self,method):
MockOrHook=self.getResultForMethod(method)
print MockOrHook
if MockOrHook=='__pass':
if hasattr(self,'Mock%s'%method):#没有的话也pass
result= getattr(self,'Mock%s'%method)()
if type(result)==type('') or type(result)==type(u''):
return result
else:
return json.dumps(result)
elif not MockOrHook is None:
return MockOrHook
return self.simpleBypass()
def run(self):
self.pathSplit=web.ctx.path.split('/')
method=self.pathSplit[-1]
return self.sendResult(method)

Mock服务主要采用webpy,我们先建立一个公共的OAuth类来统一处理。基本的处理过程如下:
1.通过请求的host不同映射到不同的具体类(继承自OAuthMock)
2.run函数判断结尾的请求方法,派发不同的处理流程
3.读取oauth.yaml,若该方式为mock,这调用Mock方法 的方法来返回,若为hook,则直接返回配置的数据,若两者都不是则直接用真实的服务器数据
按照这种思路,具体的类大概是这样的

#!/usr/bin/python
# -*- coding: utf-8 -*-
import web,requests,yaml,json,random,time
from OAuthMock import OAuthMock
class WeiXinAuth(OAuthMock):
def Mockaccess_token(self):
token=self._MockGetToken()
scope=['snsapi_base','snsapi_userinfo','snsapi_login'][random.randint(0,2)]
return {'access_token':token+'_atoken','expires_in':self.expires_in,'refresh_token':token+'_rtoken','scope':scope,'unionid':token+'_uid'}
def Mockrefresh_token(self):
token=self._MockGetToken()
retJson={'refresh_token':token+'_rtoken','access_token':token+'_atoken','expires_in':self.expires_in,'openid':token+'_openid'}
return retJson
def Mockuserinfo(self):#结构参看https://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
token=self._MockGetToken()
retJson={
'openid':token+'_opendid','nickname':'mock%s'%time.time(),
'sex':'%d'%random.randint(0,2),'city':"北京",'province':'北京',
'country':['CN','OTHER'][random.randint(0,1)],
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[
"chinaunicom"
],
"unionid": token+'_uid'
}
return retJson
def Mockauth(self):
return { "errcode":0,"errmsg":"ok"}

最后,来总结下整个ui登陆的过程
1.先检查登陆页面是否有微信登陆的按钮
2.点击后,页面的链接时候正确
3.访问特定的回调页面
4.按成功还是失败作下一步检查
  评论这张
 
阅读(217)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017