接口自动化框架

好久不更新了,今天又要杀回来了,哈哈哈哈~~~

切入正题,最近公司要求开展自动化,于是将搁置的接口自动化重新梳理了一下,晒出来以防遗忘。

接口框架有四个包组成:

1,testdata包:

      case_data.xlsx存放接口数据

     使用excel读取接口数据。首页接口信息:接口名、请求url、请求方式、是否执行等。excel从第二个sheet开始每个记录的测试数据。请求参数、依赖数据、响应结果、数据存储、是否执行、执行结果、错误信息记录

2,config包:

      PublicData.py存:存放路径、数据库配置、excel数据下标常量、全局变量

3,util包:

      ParseExcel.py:解析excel工具类

      HttpClient.py:封装了request方法,调用request方法传入参数:url,method,type,requestdata=None,header=None得到响应结果

      my_rsa_encry.py:参数加密方法,对参数进行ras加密,传入公钥和要加密的数据得到加密后的密文

4,aciton包:

      data_store.py存储数据:传入参数:case_name(接口名称),case_id(接口id),store_param(存储数据的结构),requestdata(接口的请求数据),responsedata(接口响应数据),方法执行后将数据存储到全局变量REQUEST_DATA和RESPONSE_DATA中,后续依赖数据就是从这里取值。

源码:

#coding=utf-8
from config.PublicData import REQUEST_DATA,RESPONSE_DATA
class DataStore():
    def __init__(self):
        pass
    @classmethod
    def store(cls,case_name,case_id,store_param,requestdata=None,responsedata=None):
        for k,v in store_param.items():
            if k=='request':
                # param=data:toLoginKey、mobile、pwd
                for param in v:
                    #如果保存的参数只有一个层级,直接从请求中取值
                    if param.find(':')==-1:
                        value=requestdata[param]
                    #如果保存的参数多个层级,需要拼接后再从请求中取值
                    else:
                        param_list=param.split(':')
                        value='requestdata'
                        for index in range(len(param_list)):
                            value+='["'+param_list[index]+'"]'
                        value=eval(value)
                        param=param_list[-1]
                    if REQUEST_DATA.has_key(case_name):
                        if REQUEST_DATA[case_name].has_key(case_id):
                            REQUEST_DATA[case_name][case_id][param]=value
                        else:
                            REQUEST_DATA[case_name][case_id]={param:value}
                    else:
                        REQUEST_DATA[case_name]={case_id:{param:value}}
            elif k=='response':
                # param=data:toLoginKey、mobile、pwd
                for param in v:
                    #如果保存的参数只有一个层级,直接从响应中取值
                    if param.find(':')==-1:
                        value=responsedata[param]
                    #如果保存的参数多个层级,需要拼接后再从响应中取值
                    else:
                        param_list=param.split(':')
                        value='responsedata'
                        for index in range(len(param_list)):
                            value+='["'+param_list[index]+'"]'
                        value=eval(value)
                        param=param_list[-1]
                    if RESPONSE_DATA.has_key(case_name):
                        if RESPONSE_DATA[case_name].has_key(case_id):
                            REQUEST_DATA[case_name][case_id][param]=value
                        else:
                            RESPONSE_DATA[case_name][case_id]={param:value}
                    else:
                        RESPONSE_DATA[case_name]={case_id:{param:value}}
            else:
                print 'store_param里面的数据参数来源非请求或者响应中:store_param data not from in request or response'
if __name__=='__main__':
    requestdata={"mobile":"1760034xxxx","pwd":"aaaa1111",'email':'xxx@xxx.com'}
    responsedata={u'msg': u'suc', u'params_num': None, u'code': u'0', u'params': None, u'data': {u'onlyGoogleAuth': 0, u'toLoginKey': u'OGM3YzdkNTgtMjkyZi00ODA3LTg4ZmUtMzg2YTU1NWQ0OTE5MTU4Mzc2MjYwMTIwMA%3D%3D', u'email': u'xxxn@xxx.com', u'googleAuth': 1, u'mobileAuth': 1, u'emailAuth': 0, u'showAc': 0}}
    store_param={"response":["data:toLoginKey"],'request':['mobile','pwd']}
    print REQUEST_DATA,RESPONSE_DATA
    DS=DataStore()
    for i in range(2):
        DS.store('login',str(i),store_param,requestdata,responsedata)
    print REQUEST_DATA
    print RESPONSE_DATA

store_param格式为:store_param={"response":["data:toLoginKey"],'request':['mobile','pwd']}

requestdata={"mobile":"1760034xxxx","pwd":"aaaa1111",'email':'xxx@xxx.com'}

responsedata={u'msg': u'suc', u'params_num': None, u'code': u'0', u'params': None, u'data': {u'onlyGoogleAuth': 0, u'toLoginKey': u'OGM3YzdkNTgtMjkyZi00ODA3LTg4ZmUtMzg2YTU1NWQ0OTE5MTU4Mzc2MjYwMTIwMA%3D%3D', u'email': u'xxxn@xxx.com', u'googleAuth': 1, u'mobileAuth': 1, u'emailAuth': 0, u'showAc': 0}}

REQUEST_DATA={'login': {'1': {'mobile': '1760034xxxx', 'pwd': 'aaaa1111'}, '0': {'mobile': '1760034xxxx', 'pwd': 'aaaa1111'}}} RESPONSE_DATA={'login': {'1': {'toLoginKey': u'OGM3YzdkNTgtMjkyZi00ODA3LTg4ZmUtMzg2YTU1NWQ0OTE5MTU4Mzc2MjYwMTIwMA%3D%3D'}, '0': {'toLoginKey': u'OGM3YzdkNTgtMjkyZi00ODA3LTg4ZmUtMzg2YTU1NWQ0OTE5MTU4Mzc2MjYwMTIwMA%3D%3D'}}}

getrely.py:组装请求数据。有些请求数据需要依赖其他接口的请求后者响应数据。这个类就是为了根据依赖关系从新组装请求数据。

源码:

#coding=utf-8
from util.my_rsa_encry import myencry
from util.my_rsa_decry import mydecry
class GetKey():
    def __init__(self):
        pass
    #根据依赖数据的结果从RESTDATA,RESPONSEDATA里面取值放到requstdata中
    def get(self,case_name,requestdata,relaydata,RESTDATA,RESPONSEDATA):
        for relay_param,relay_path in relaydata.items():
            for requst_or_response,case_path in relay_path.items():
                casename,case_id=case_path.split('->')
                #依赖数据中存在“:”,所以依赖的数据不是单纯根据caseid取值,是有对应关系的。
                if case_id.find(":")!=-1:
                    id,store_parem=case_id.split(':')
                    #从存储请求数据的常量REQUEST中取值
                    if requst_or_response=='request':
                        value=RESTDATA[casename][id][store_parem]
                        requestdata[relay_param]=value
                    #从存储响应数据的常量RESPONSE中取值
                    if requst_or_response=='response':
                        value=RESPONSEDATA[casename][id][store_parem]
                        requestdata[relay_param]=value
                #依赖数据中没有’:‘,依赖数据直接从datastore里面取值
                else:
                     #从存储请求数据的常量REQUEST中取值
                    if requst_or_response=='request':
                        value=RESTDATA[casename][case_id][relay_param]
                        requestdata[relay_param]=value
                    #从存储响应数据的常量RESPONSE中取值
                    if requst_or_response=='response':
                        value=RESPONSEDATA[casename][case_id][relay_param]
                        requestdata[relay_param]=value
        if case_name=='login_verify':
            pk=requestdata['pk']
            en=myencry(pk)
            mobile=requestdata['mobileNumber']
            pwd=requestdata['loginPword']
            requestdata['mobileNumber']=en.get_encry_str(mobile)
            requestdata['loginPword']=en.get_encry_str(pwd)
        return requestdata

if __name__=='__main__':
    #存在问题:依赖的参数名和存储数据的参数名不一致,这样就无法从存储数据中找到依赖数据。
    #改进:在依赖数据中加入对应关系。请求的参数对应响应的参数名
    requestdata={"lang": "zh_CN", "mobileNumber":"${rsa(xxxn@cxxx.com)}" , "loginPword":"${rsa(xxxx)}" , "recaptcha": "", "pk": "", "genkey": ""}
    relaydata={"mobileNumber":{"request":"login->1"},'loginPword':{"request":"login->2"},"pk":{"response":"get_pk->1:data"}}
    RESTDATA={'login':{'1':{'mobileNumber':'xxxx','loginPword':'aaaa1111'},'2':{'mobileNumber':'xxxx','loginPword':'aaaa1111','other':"aaa"}},'register':{'1':{'name':"xxx"}}}
    RESPONSEDATA={'get_pk':{'1':{'data':'PK_VALUE'},'2':{'mobileNumber':'xxx','loginPword':'xxx','other':"xx"}},'register':{'1':{'name':"xxx"}}}
    getkey=GetKey()
    print getkey.get(requestdata,relaydata,RESTDATA,RESPONSEDATA)
    {"response":{"genkey":"login_1->3"}}
    {"genkey":{'response':'login_1->3'}}

check_result.py:结果校验。

源码:

#coding=utf-8
import re
def check(checkpoint,responsedata,errorinfo):
    errorinfo={}
    for k,v in checkpoint.items():
        #从响应中取值要匹配的值
        param=''.join(map(lambda x:'[\'%s\']' %x,k.split(':')))
        try:
            value=eval('responsedata'+param)
        except Exception,e:
            print 'responsedata not have %s' %param
        #检查内容需要正则匹配
        if isinstance(v,dict):
            for type,patten in v.items():
                patten=re.compile(patten)
                if type=='type':
                    try:
                        re.search(patten,value).group()
                    except Exception,e:
                        errorinfo[k]=value
        #检查内容值匹配
        else:
            if value!=v:
                errorinfo[k]=value
    if len(errorinfo.keys())==0:
        return None
    else:
        return errorinfo

if __name__=='__main__':
    a='xxx@qq.com'
    responsedata={u'msg': u'suc', u'params_num': None, u'code': u'0', u'params': None, u'data': {u'onlyGoogleAuth': 0, u'toLoginKey': u'OTA4Y2Q0MDktMDA5OC00NGJiLWE1YjMtMzQ5ODE4Yjg0OTlhMTU4NDAyODE5NzkzNA%3D%3D', u'email': u'xxx@qq.com', u'googleAuth': 1, u'mobileAuth': 0, u'emailAuth': 0, u'showAc': 0}}
    checkpoint={'data:showAc':0,'data:email':{'type':'.*@.*\.com'},'msg':'suc'}
    errorinfo={'msg':'aaa'}
    print check(checkpoint,responsedata,errorinfo)

write_result.py:将请求结果、断言结果写入excel。

源码:

from config.PublicData import *
def write(excel,case_detail_sheet,case_detail_idx,responsedata,errorinfo):
    excel.writeCell(case_detail_sheet,str(responsedata),rowNo=case_detail_idx,colsNo=ResponseData)
    if errorinfo:
        # writeCell(self, sheet, content, coordinate = None,rowNo = None, colsNo = None, style = None):
        excel.writeCell(case_detail_sheet,'fail',rowNo=case_detail_idx,colsNo=Status,style='red')
        excel.writeCell(case_detail_sheet,str(errorinfo),rowNo=case_detail_idx,colsNo=ErrorInfo)
    else:
        excel.writeCell(case_detail_sheet,'pass',rowNo=case_detail_idx,colsNo=Status)

接口框架入口:读取excel第一页获取接口信息,根据接口名获取接口的请求数据。请求需要依赖数据则调用依赖方法将请求拼接完成。调用请求接口方法获得接口响应数据。如果需要保存数据则调用数据保存方法进行保存,最后检查结果,将接口执行的结果和错误日志写入excel

搭建框架过程中出现的问题:

      1.依赖参数和存储名字不一致:比如下单接口需要传入token,token由登录接口返回。但是登录接口返回的token参数名为data。开始设置框架的时候,没考虑到这一点,取不到依赖数据。后来框架中加入了参数的对应关系:token依赖于login接口响应值中的data值

      2,读取excel内容的时候。开始封装的excel方法取行和列数字的时候只是传了行列下标。这样在读取的时候如果涉及到不同sheet的数据,还要在入口方法中切换sheet,非常容易读取错误。所以excel封装了新方法,获取行列数据的时候传入sheet。这样就可以清晰的知道要取哪一个sheet中的航和列。不会因为忘记切换sheet而取错数据。

      3,数据存储。 定义REQUEST和RESPONES字典类型存储依赖数据。存放在config的参数文件为全局变量。 封装数据存储的时候,应该是直接往里面放入存储的数据。比如:RQUEST[casename]={} 但是在组织数据的时候不小心直接给REQUEST赋值了(REQUEST={...});把REQUEST和RESPONES重新复制,相当于方法的私有变量,重新开启了内存空间。导致全局没有复制。后续从存储数据中取值没有取出来

不完善的地方:

      1,断言函数:校验只局限于校验响应结果,没有关联数据库。比如下单接口返回与接口文档一致,但是用户账户扣款未校验。

      2,执行结果只写到了excel中,应该介入报警邮件即使响应

      3,excel结构:一个接口一个sheet,接口太多不好维护

以上就是整体的框架结构,附上框架源码链接: https://pan.baidu.com/s/1gXBCzUu19S1H8h1IpuHLVw 提取码: 6pfr 

有兴趣的小伙伴可以继续改进,bye~~

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值