背景

因为服务的迁移,Jira版本的更新,很多接口文档的维护变少,导致想要编写部分服务的自动化测试变得尤为麻烦,很多服务,尤其是客户端接口需要通过抓包的方式查询参数来编写自动化用例,但是过程中手工重复操作过多,不利于RF用例的快速覆盖,本文给大家介绍如何通过解析抓包拦截的数据,转化为测试关键字并生成测试用例。

实现

抓包

如何安装抓包工具在本文就不赘述了,抓包,过滤出想要的数据,导出,保存的格式注意选择为har

数据解析

感兴趣的小伙伴可以直接查看导出的har文件内容,它是一个标准的JSON格式的数据,所有的请求数据都在data["log"]["entries"]下。

需要注意的有以下几点,

注意点 解决方法
接口返回数据一般使用的base64进行加密 base64.b64decode()
标准JSON null等参数与Python不一致 replace("true", "True")
method=Get时,request["queryString"]
request["postData"]["text"] request["postData"]["params"]
header中存在多个无需使用的信息,abandon_headers

根据请求数据生成关键字名称

def gen_filename(url, method):
"""
根据url生成方法名
:param url:
:param method:
:return:
"""
filename = ""
path = str(url).split("/")
# print(path)
# print(len(path))
if len(path) == 2 and method == "GET":
filename = filename + path[1].split("?")[0]
return filename
if len(path) == 2 and method == "DELETE":
filename = filename + path[1].split("?")[0]
return filename for i in range(len(path)):
if i == 1:
filename = filename + path[i]
if "." in filename:
filename = filename.split(".")[1]
filename = filename + "_"
continue
if i == 2: # 第一个path小写
if "?" in path[i]:
filename = filename + path[i].capitalize().split("?")[0]
break
filename = filename + path[i]
continue
if i == len(path) - 1 and method.upper() == "GET":
filename = filename + path[i].capitalize().split("?")[0]
break
filename = filename + path[i].capitalize()
return filename

完整代码

#! /usr/bin/python
# coding:utf-8
"""
@author:Bingo.he
@file: har_parse.py
@time: 2019/01/01
"""
import os
import json
import xlrd
import copy
import base64
from apitest.Common.Testscript.utils.logger import logger
from xlutils import copy def save_suits(keyword_filename, datas, file_path, ignore_same_file=None):
"""保存excel数据
:param ignore_same_file:
:param file_path:
:param keyword_filename:
:param datas:
:return:
"""
book = xlrd.open_workbook("source_xls/templates/kw_template.xls", formatting_info=True, encoding_override="utf8")
new_book = copy.copy(book) # 复制读取的Excel
sheet = new_book.get_sheet(0) # 取第一个sheet页
line_num = 1
parameter, value, description, parameter_type, data_type, exp, _type, url, group, documentation, headers, _ = datas if len(str(exp)) > 30000:
exp = {"data": "返回数据过大"}
sheet.write(line_num, 0, u'%s' % parameter)
sheet.write(line_num, 1, u'%s' % value)
sheet.write(line_num, 2, u'%s' % description)
sheet.write(line_num, 3, u'%s' % parameter_type)
sheet.write(line_num, 4, u'%s' % data_type) try:
pass
except Exception as e:
logger.error(e)
if isinstance(exp, dict):
pass
else:
exp = str(exp[2:-1])
sheet.write(line_num, 5, u'%s' % eval(json.dumps(str(exp))))
sheet.write(line_num, 6, u'%s' % _type)
sheet.write(line_num, 7, u'%s' % url)
sheet.write(line_num, 8, u'%s' % group)
sheet.write(line_num, 9, u'%s' % documentation)
sheet.write(line_num, 10, u'%s' % headers)
if not os.path.exists(file_path):
os.makedirs(file_path)
if keyword_filename:
target_filename = os.path.abspath(os.path.join(file_path, '{}.xls'.format(keyword_filename)))
if os.path.exists(target_filename) and not ignore_same_file:
raise Exception
new_book.save(target_filename) # 保存修改过后复制的Excel
logger.info("关键字【{}】文件保存成功,保存于【{}】目录".format(keyword_filename, file_path)) class HarParse:
@staticmethod
def get_har_data(har_filename):
"""读取传入的har文件,返回 关键字文件名 及 对应数据 的键值对
:param har_filename:
:return:
""" with open(har_filename, "r", encoding="utf8") as f:
data = f.readlines()
return json.loads(data[0])["log"]["entries"] def parse_data(self, har_file, domain_endpoint):
reqs = self.get_har_data(har_file)
xls_datas = {} for req in reqs:
request = req["request"]
headers_str = self.gen_header_data(request["headers"]) method = request["method"]
url = request["url"].split(domain_endpoint)[1] resp = req["response"]
base64_content_text = resp["content"]["text"] try:
resp_text = base64.b64decode(base64_content_text).decode().replace("false", "False").\
replace("null", "None").replace("true", "True")
except Exception as e:
logger.error("请求【{}】method:【{}】返回结果-base64-转化出错".format(request["url"], method))
logger.error("错误原因:【{}】".format(e))
continue
filename = self.gen_filename(url, method) keys = [i.upper() for i in xls_datas.keys()]
if filename.upper() in keys:
filename = filename + method.upper() content_type = "urldecode" if method.upper() == "GET":
url = url.split("?")[0]
query_strs = request["queryString"] post_data = {}
for query_str in query_strs:
post_data[query_str["name"]] = query_str["value"]
else:
content_type = "json" # application/json
try:
post_data = request["postData"]["text"]
except KeyError:
post_data = request["postData"]["params"] # request["headers"]
data = ["data", post_data, "", content_type, "", resp_text, method, url, "", self.doc(), headers_str,
request["headers"]] xls_datas[filename] = data logger.info("抓取的URL为【{}】".format(request["url"]))
logger.info("获取对应PATH为【{}】".format(url))
logger.info("对应将生成的文件名称为【{}】".format(filename))
logger.info("=============================分割线===============================") # logger.info(json.dumps(xls_datas.keys(), indent=4, ensure_ascii=False))
return xls_datas @staticmethod
def gen_filename(url, method):
"""
根据url生成方法名
:param url:
:param method:
:return:
"""
filename = ""
path = str(url).split("/")
# print(path)
# print(len(path))
if len(path) == 2 and method == "GET":
filename = filename + path[1].split("?")[0]
return filename
if len(path) == 2 and method == "DELETE":
filename = filename + path[1].split("?")[0]
return filename for i in range(len(path)):
if i == 1:
filename = filename + path[i]
if "." in filename:
filename = filename.split(".")[1]
filename = filename + "_"
continue
if i == 2: # 第一个path小写
if "?" in path[i]:
filename = filename + path[i].capitalize().split("?")[0]
break
filename = filename + path[i]
continue
if i == len(path) - 1 and method.upper() == "GET":
filename = filename + path[i].capitalize().split("?")[0]
break
filename = filename + path[i].capitalize()
return filename @staticmethod
def gen_header_data(headers):
headers_str = ""
for i in headers:
abandon_headers = ["Host", "User-Agent", "Accept-Encoding", "Accept", "Connection", "Content-Length"]
if i["name"] in abandon_headers:
continue
headers_str = headers_str + i["name"] + "=" + i["value"] + " " return headers_str @staticmethod
def doc():
return """
... 【功能】
...
... 【参数】
... url: 请求域名
... data: 请求参数
...
... 【返回值】
... Ret: response对象
"""

【Robot Framework 项目实战 04】基于录制,生成RF关键字及 自动化用例的更多相关文章

  1. 【Robot Framework 项目实战 03】使用脚本自动生成统一格式的RF自动化用例

    背景 虽然大家都已经使用了统一的关键字,但是在检查了一些测试用例之后,还是发现因为大家对RF的熟悉程度不一导致的测试用例颗粒度差异很大的情况:而且在手动方式转化测试用例过程中,有不少工作是完全重复的且 ...

  2. 【Golang】基于录制,自动生成go test接口自动化用例

    背景 之前写过一篇博客,介绍怎么用Python通过解析抓包数据,完成自动化用例的编写.最近这段时间在使用go test,所以就在想能不能也使用代码来生成自动化用例,快速提升测试用例覆盖率.说干就干. ...

  3. 【Robot Framework 项目实战 02】使用脚本生成统一格式的RF关键字

    背景 在微服务化的调用环境下,测试数据及接口依赖的维护是一个问题,因为依赖的接口和数据可能不在同一个服务下,而这相关的多个服务往往是不同人员来测试的. 因此为了节省沟通成本,避免关键字的重复冗余.所以 ...

  4. 【Robot Framework 项目实战 01】使用 RequestsLibrary 进行接口测试

    写在前面 本文我们一起来学习如何使用Robot Framework 的RequestsLibrary库,涉及POST.GET接口测试,RF用例分层封装设计等内容. 接口 接口测试是我们最常见的测试类型 ...

  5. 【Robot Framework 项目实战 00】环境搭建

    前言 我们公司在推广RF这个框架做后端接口测试,力求让同事们能更快的完成服务端需求的自动化,作为主导者之一,决定分享一些经验,方便后来者. 我会从安装部署.Request.selenium.自定义框架 ...

  6. 【Robot Framework 项目实战 02】SeleniumLibrary Web UI 自动化

    前言 SeleniumLibrary 是针对 Robot Framework 开发的 Selenium 库.它也 Robot Framework 下面最流程的库之一.主要用于编写 Web UI 自动化 ...

  7. 自动化测试框架Cucumber和Robot Framework的实战对比

    自动化测试框架Cucumber和RobotFramework的实战对比 一.摘要 自动化测试可以快速自动完成大量测试用例,节约巨大的人工测试成本:同时它需要拥有专业开发技能的人才能完成开发,且需要大量 ...

  8. SDKStyle的Framework项目使用旧版项目文件生成的Nuget包遇到的问题

    随笔-2021-11-10 SDKStyle的Framework项目使用旧版项目文件生成的Nuget包遇到的问题 简介 C#从NetCore之后使用了新版的项目文件,SDK-Style项目,新版本的项 ...

  9. Robot Framework 项目搭建

    首先新建一个项目“RobotDemo".项目Type一般选择“Directory”形式. 项目第一层可以放3种文件:Test Suite.Directory 和 Resource File. ...

随机推荐

  1. @PostConstruct注解原理解析

    所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 正文 @PostConstruct注解使用简介 在了解一个东西的原理之前,我们得初步的懂得如何 ...

  2. linux设置密钥登录(只允许密钥登录)

    一.root用户使用这条命令看看家目录有没有(.ssh文件夹),cd .ssh,如果存在就会进入这个文件夹,不存在就(makedir .ssh),修改.ssh这个文件夹权限(chmod 700 .ss ...

  3. Ubuntu 远程管理常用命令

    目标 关机/重启 shutdown 查看或配置网卡信息 ifconfig ping 远程登录和复制文件 ssh scp 01. 关机/重启 序号 命令 对应英文 作用 01 shutdown 选项 时 ...

  4. FPGA学习笔记——点亮LED

    软件平台:win7(64bit) + Quartus II 9.1 (64-Bit) 硬件平台:东理电子Easy-FPGA Cyclone II EP2C5T114C8N 这个开发板买了很长时间了,买 ...

  5. 微信小程序开发(十二)Promise将异步改为同步

    // utils/utils.js /** * requestPromise用于将wx.request改写成Promise方式 * @param:{string} myUrl 接口地址 * @retu ...

  6. MySQL在使用group_concat()函数数据被截取

    遇到问题: 项目中有个需求,MySQL中存储的是树状的数据.现在给出一个节点,需要从Mysql数据库中取出这个节点下所有的节点.采用MySQL的函数. 函数如下: CREATE DEFINER=`ro ...

  7. Centos7下安装MongoDB4.0.10

    前言 模式自由 :可以把不同结构的文档存储在同一个数据库里 面向集合的存储:适合存储 JSON风格文件的形式 完整的索引支持:对任何属性可索引 复制和高可用性:支持服务器之间的数据复制,支持主-从模式 ...

  8. python获取本机的IP

    转载:https://www.cnblogs.com/whu-2017/p/8986842.html 方法一: 通常使用socket.gethostbyname()方法即可获取本机IP地址,但有时候获 ...

  9. Angular4的dom事件

    Angular4的dom事件 差值表达式和属性绑定其实是一样的(例) <!-- 这两个是一样的效果,使用哪个都可以 --> <img src="{{imgUrl}}&quo ...

  10. 快捷键IntelliJ IDEA For Mac

    http://www.cnblogs.com/wxd0108/p/5295017.html Mac键盘符号和修饰键说明 ⌘ Command ⇧ Shift ⌥ Option ⌃ Control ↩︎  ...