51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 3555|回复: 3
打印 上一主题 下一主题

[转贴] PICT 组合 +PageObject+Python asyncio 接口测试

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2017-6-28 11:27:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
说明
全对偶接口生成参数
功能
python3.4 asyncio aiohttp
unittest参数化
pageobject
数据维护用的YMAL
基于PICT全对偶生成接口参
代码分析
aiohttp asyncio 封装

  1. <span style='color: rgb(68, 68, 68); text-transform: none; text-indent: 0px; letter-spacing: 0.45px; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; background-color: rgb(249, 249, 249); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>class request():
  2.     def __init__(self, **kwargs):
  3.         '''
  4.         http请求的封装,传入dict
  5.         :param req:
  6.         '''
  7.         self.req = kwargs
  8.     def get(self, url, param):
  9.         data = {}
  10.         _url = self.req["protocol"] + self.req["host"] + ":" + str(self.req["port"]) + url
  11.         print(_url +" get请求参数为:"+str(param))
  12.         try:
  13.             response = yield from aiohttp.request("GET", _url, headers=self.req["header"], params=param)
  14.             string = (yield from response.read()).decode('utf-8')
  15.             if response.status == 200:
  16.                 data = json.loads(string)
  17.             else:
  18.                 print("data fetch failed for")
  19.                 print(response.content, response.status)
  20.             data["status_code"] = response.status
  21.             print(data)
  22.         except asyncio.TimeoutError:
  23.             print("访问失败")
  24.         except UnicodeDecodeError:
  25.             print("接口崩溃了")
  26.         return data
  27.     def post(self,url, param):
  28.         data = {}
  29.         _url = self.req["protocol"] + self.req["host"] + ':' + str(self.req["port"]) + url
  30.         print(_url + " post接口参数为:" + str(param))
  31.         try:
  32.             response = yield from aiohttp.request('POST', _url, data=json.dumps(param), headers=self.req["header"])
  33.             string = (yield from response.read()).decode('utf-8')
  34.             if response.status == 200:
  35.                 data = json.loads(string)
  36.             else:
  37.                 print("data fetch failed for")
  38.                 print(response.content, response.status)
  39.             data["status_code"] = response.status
  40.             print(data)
  41.         except asyncio.TimeoutError:
  42.             print("访问失败")
  43.         return data


  44. def asyn(fun):
  45.     loop = asyncio.get_event_loop()
  46.     tasks = asyncio.ensure_future(fun)
  47.     loop.run_until_complete(tasks)
  48.     # loop.close()
  49.     print('Task ret: {}'.format(tasks.result()))
  50.     return tasks.result()</span>
复制代码

请求参数的处理
  1. <span style='color: rgb(68, 68, 68); text-transform: none; text-indent: 0px; letter-spacing: 0.45px; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; background-color: rgb(249, 249, 249); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>def paramsFilter(params):
  2.     '''
  3.     请求参数处理
  4.     :param params:
  5.     :return:
  6.     '''

  7.     result = {}
  8.     for wap_key in params:
  9.         for son_key in params[wap_key]:
  10.             if params[wap_key]["error"] == "0" or params[wap_key]["error"] == "1" or params[wap_key]["error"] == "2": # 过滤和处理相关请求参数
  11.                 result[wap_key] = changeFormat(params[wap_key]["type"], params[wap_key]["input"])
  12.             break
  13.     return result


  14. def changeFormat(key, param):
  15.     '''
  16.     请求参数类型处理
  17.     :param key:
  18.     :param param:
  19.     :return:
  20.     '''
  21.     param_type = {
  22.         "str": lambda: str(param),
  23.         "int": lambda: int(param),
  24.         "float": lambda: float(param),
  25.         "bool": lambda: bool(param)
  26.     }
  27.     return param_type[key]()

  28. def readReq(param):
  29.     '''
  30.     读取请求的url
  31.     :param param:
  32.     :return:
  33.     '''
  34.     return param.split("|") # 1 用例id,2 用例介绍,3 url

  35. def readParam(param):
  36.     '''
  37.     读取准备的pict参数
  38.     param1:...
  39.     param2:..
  40.     :return: list
  41.     '''
  42.     result = []
  43.     _param2 = ""
  44.     for item in param:
  45.         for key in item:
  46.             tempParam = item[key].split("&")
  47.             _param = ""
  48.             for tItem in tempParam:
  49.                 tiParam = tItem.split("|")
  50.                 if len(tiParam) == 5:
  51.                     _param = _param + "," + key + ":error:" + tiParam[0] + ":input:" + tiParam[1] + ":type:" + tiParam[
  52.                         2] + ":" + tiParam[3] + ":" + tiParam[4]
  53.                 else:
  54.                     _param = _param + "," + key + ":error:" + tiParam[0] + ":" + tiParam[1] + ":" + tiParam[2]
  55.             _param2 = _param2 + "," + _param
  56.             result.append(key + ":"+_param[1:])
  57.             break
  58.     return result


  59. def readPictParam(paramRequestPath):
  60.     '''
  61.     读取本地e生成好了的接口请求参数
  62.     :param paramRequestPath:  已经处理好的pict参数路径
  63.     :return: list
  64.     '''
  65.     result = read(paramRequestPath)
  66.     l_result = []
  67.     if result:
  68.         for info in range(len(result)):
  69.             for item in range(len(result[info])):
  70.                 t_result = result[info][item].split(",")
  71.                 d_t = {}
  72.                 for i in t_result:
  73.                     temp = i.split(":")
  74.                     t = {}
  75.                     t[temp[1]] = temp[2]
  76.                     if len(temp) > 5: #如果大于5,说明全部参数为8:如 :' {'rep': 'dict', 'type': 'str', 'input': '""', 'error': '2'}
  77.                         t[temp[3]] = temp[4]
  78.                         t[temp[5]] = temp[6]
  79.                         t[temp[7]] = temp[8]
  80.                     else:
  81.                         t[temp[3]] = temp[4] # 参数至少
  82.                     d_t[temp[0]] = t
  83.                 l_result.append(d_t)
  84.     return l_result


  85. def pairPatchParam(**kwargs):
  86.     '''
  87.        pict生成请求参数
  88.        :param kwargs:
  89.        params: 请求的参数列表,类型为list
  90.        paramPath: 用例目录
  91.        paramRequestPath: 已生成用例目录
  92.        :return:
  93.        '''

  94.     for item in kwargs["params"]:
  95.         write(kwargs["paramPath"], item)
  96.     os.popen("pict " + kwargs["paramPath"] + ">" + kwargs["paramRequestPath"])
  97.     time.sleep(1)</span>

复制代码
实例-登录
配置init.yaml
  1. <font face="宋体"><pre style='border-width: 1px 0px; margin: 0px -15px 20px; padding: 5px 15px; border-radius: 0px; color: rgb(68, 68, 68); text-transform: none; line-height: 1.4285; text-indent: 0px; letter-spacing: 0.45px; overflow: auto; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; border-top-color: rgb(240, 240, 240); border-bottom-color: rgb(240, 240, 240); border-top-style: solid; border-bottom-style: solid; display: block; word-break: break-all; word-wrap: break-word; box-sizing: border-box; orphans: 2; widows: 2; background-color: rgb(249, 249, 249); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; border-image: initial;' class="highlight plaintext"><code style='margin: 2px; padding: 0px !important; border-radius: 3px; border: currentColor !important; color: rgb(68, 68, 68) !important; line-height: 18px; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 12px !important; display: block; white-space: pre-wrap; word-break: break-all; box-sizing: border-box; background-color: rgb(249, 249, 249) !important;'>title: XXXX接口测试
  2. host: baidu.com
  3. port: 8443
  4. protocol: https://
  5. header: {account": "XX", "Content-Type": "application/json; charset=UTF-8","secrectKey": "XXX=","appID": "XX"}
  6. </code></pre><p style='margin: 0px 0px 20px; color: rgb(34, 37, 39); text-transform: none; line-height: 26px; text-indent: 0px; letter-spacing: 0.45px; font-family: Helvetica, Arial, "PingFang SC", "Noto Sans", Roboto, "Microsoft Yahei", sans-serif; font-size: 15px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: normal; box-sizing: border-box; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'><strong style="color: rgb(0, 0, 0); font-weight: 700; box-sizing: border-box;"></strong> </p></font>
复制代码
配置用例yaml


  1. <span style='color: rgb(68, 68, 68); text-transform: none; text-indent: 0px; letter-spacing: 0.45px; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; background-color: rgb(249, 249, 249); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>req: 1001|登录|/XX/login|POST
  2. param:
  3.   - name: 0|swx458348|str|rep|dict&1|swx4583481|str|rep|dic&3|rep|dict
  4.   - XX: 0|fnNoaWt1bjE5ODk|str|rep|dict&1|fnNoaWt1bjE5ODk1|str|rep|dic&3|rep|dict

  5. #error: 0正常,1错误的值,2类型错误,3不传字段,4后面再扩展如最大,最小
  6. #rep:后面是检查点,支持
  7. #{} ,对应key为Dict
  8. #{[]},对应key为DictList
  9. #{[{},{}]} 对应key为DictListDict
  10. </span>
复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

该用户从未签到

2#
 楼主| 发表于 2017-6-28 11:32:13 | 只看该作者
本帖最后由 小爸爸 于 2017-6-28 11:35 编辑

PageObject

  1. <p><span style='color: rgb(68, 68, 68); text-transform: none; text-indent: 0px; letter-spacing: 0.45px; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; background-color: rgb(249, 249, 249); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>class Login:
  2.     '''
  3.     kwargs:
  4.     path: 用例文件目录
  5.     initPath: 请求头部目录
  6.     '''

  7.     def __init__(self, **kwargs):
  8.         self.path = kwargs["path"]  # 用例yaml目录
  9.         self.param = getYam(self.path)["param"]  # 请求参数
  10.         self.req = getYam(self.path)["req"]  # 请求url
  11.         self.readParam = readParam(self.param)  # 读取并处理请求参数
  12.         pairPatchParam(params=self.readParam, paramPath=PATH("../Log/param.log"),
  13.                        paramRequestPath=PATH("../Log/paramRequest.log"))  # pict生成参数
  14.         self.getParam = readPictParam(paramRequestPath=PATH("../Log/paramRequest.log"))  # 得到pict生成的参数
  15.         self.readReq = readReq(self.req)  # 0 用例id,1 用例介绍,2 url,3 mehtod
  16.         print(self.readReq)
  17.         self.head = requestHead(kwargs["initPath"]) # initPath 请求头准备
  18.         print(self.head)
  19.         # self.head = requestHead(PATH("../yaml/init.yaml"))  # protocol ,header,port,host,title

  20.     '''
  21.     发请求
  22.     '''

  23.     def operate(self):
  24.         for item in self.getParam:
  25.             param = paramsFilter(item) # 过滤接口,如果有其他加密,可以自行扩展
  26.             f = request(header=self.head["header"], host=self.head["host"], protocol=self.head["protocol"], port=self.head["port"])
  27.             if self.readReq[3] == "POST":
  28.                 BaseAsy.asyn(f.post(self.readReq[2], param=param))
  29.             else:
  30.                 BaseAsy.asyn(f.get(self.readReq[2], param=param))
  31. </span>
  32. </p>
复制代码
test
  1. <span style='color: rgb(68, 68, 68); text-transform: none; text-indent: 0px; letter-spacing: 0.45px; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; background-color: rgb(249, 249, 249); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>from PageObject.PageLogin import Login

  2. PATH = lambda p: os.path.abspath(
  3.     os.path.join(os.path.dirname(__file__), p)
  4. )


  5. class LoginTest(unittest.TestCase):

  6.     def testLogin(self):
  7.         login = Login(path=PATH("../yaml/login.yaml"), initPath=PATH("../yaml/init.yaml"))
  8.         login.operate()
  9. )
  10. </span>
复制代码

代码入口实例
  1. <span style='color: rgb(68, 68, 68); text-transform: none; text-indent: 0px; letter-spacing: 0.45px; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; background-color: rgb(249, 249, 249); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>from Base.BaseRunner import ParametrizedTestCase
  2. from test.TestLogin import LoginTest

  3. def runnerCase():
  4.     starttime = datetime.now()
  5.     suite = unittest.TestSuite()
  6.     suite.addTest(ParametrizedTestCase.parametrize(LoginTest))
  7.     unittest.TextTestRunner(verbosity=2).run(suite)
  8.     endtime = datetime.now()
  9. if __name__ == '__main__':
  10.     runnerCase()</span>
复制代码

结果执行过程
  1. <span style='color: rgb(68, 68, 68); text-transform: none; text-indent: 0px; letter-spacing: 0.45px; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; background-color: rgb(249, 249, 249); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>https://XXX post接口参数为:...
  2. Task ret: {'status_code': 409}
  3. https://XXX post接口参数为:{}
  4. {'status_code': 400}
  5. Task ret: {'status_code': 400}
  6. https://XXX/login post接口参数为:....
  7. {'status_code': 200, 'resultCode': 0, 'info': 'Success', '...
  8. https:/...r/login post接口参数为:{'name': 'XXX', 'pwd': 'XXX'}
  9. {'status_code': 409}
  10. ....
  11. [[{'param': {'XX': 'AAAAAAAAAAAA'}, 'result': {'status_code': 409}, 'url': '/XX/login', 'method': 'POST'}, {'param': {}, 'result': {'status_code': 400}, 'url': '/XX/login', 'method': 'POST'}, {'param': {'name': 'aa', 'XX': 'AAAAAAAAAAAA'}, 'result': {'data': {'resultList': {'token': '5A2EFCE9F0C12EF99D8D18D930D7B71E:8CD9AFC8F3FB5B6B072FAE403A522D9040769B62FB557F90786DF4FFC1AF6356BA269B6E8905197B5B55359D0066146A', 'result': 'success'}}, 'resultCode': 0, 'info': 'Success', 'status_code': 200}, 'url': '/XX/login', 'method': 'POST'}, {'param': {'name': 'aa', 'XX': 'AAAAAAAAAAAA1'}, 'result': {'status_code': 409}, 'url': '/XX/login', 'method': 'POST'}, {'param': {'name': 'aa1', 'XX': 'AAAAAAAAAAAA'}, 'result': {'status_code': 409}, 'url': '/XX/login', 'method': 'POST'}, {'param': {'XX': 'AAAAAAAAAAAA1'}, 'result': {'status_code': 409}, 'url': '/XX/login', 'method': 'POST'}, {'param': {'name': 'aa'}, 'result': {'status_code': 400}, 'url': '/XX/login', 'method': 'POST'}, {'param': {'name': 'aa1'}, 'result': {'status_code': 400}, 'url': '/XX/login', 'method': 'POST'}, {'param': {'name': 'aa1', 'XX': 'AAAAAAAAAAAA1'}, 'result': {'status_code': 409}, 'url': '/XX/login', 'method': 'POST'}]]



  12. ......
  13. </span>
复制代码

回复 支持 反对

使用道具 举报

该用户从未签到

3#
发表于 2017-6-28 17:32:27 | 只看该作者
楼主你这是针对参数少的,像我们公司接口都是20多个参数,难道也这样去排列组合?那接口多的话是不是太耗时间
回复 支持 反对

使用道具 举报

  • TA的每日心情
    无聊
    2024-7-12 13:16
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]测试小兵

    4#
    发表于 2017-6-28 17:32:57 | 只看该作者
    有个疑问, 一组要求顺序POST的请求, 可以用 asyncio 吗
    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-14 14:04 , Processed in 0.062607 second(s), 22 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表