背景

因为服务的迁移,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. 解决wpscan无法更新

    如果wpscan无法更新的话 一般的原因都是源或者更新地址无法访问 下面解决 updatedb #先更新一下系统的索引 locate wpscan #定位到wpscan的目录 大概就是updater. ...

  2. 6.NIO2-Path、Paths、Files

    NIO.2 jdk1.7中,java对 NIO 极大的扩展,主要增强的是对文件处理 和 文件系统特性的支持 关于其中一些API的使用 public class TestNIO_2_Path_File ...

  3. java利用MultipartRequest的getFileName方法不能得到原文件名问题

    想利用MultipartRequest的getFileName方法来一次获取多个上传的文件名字时,得到的不是文件的名字,而是 input 的name属性 最后找到了答案,解决方法,参照http://s ...

  4. 补充:HTML标签和CSS

    角标标签: 上角标:sup 下角标:sub <!DOCTYPE html> <html> <head> <meta charset="UTF-8&q ...

  5. 通用mapper接口已经写好的 根据 list 集合查询 相应数据

    package tk.mybatis.mapper.additional.idlist; import org.apache.ibatis.annotations.Param; import org. ...

  6. Django hrf:权限、频率控制

    一.权限 二.频率控制 一.权限 1.权限介绍 只有超级用户才能访问指定的数据,所以就要用权限组件进行设置 2.局部使用 # 单独抽出写一个视图类 from rest_framework.permis ...

  7. jquery中的ajaxSetup

    在项目开发中如果我们想给某一个页面中的所有的ajax设置统一的参数的情况下,可以是使用ajaxSetup,非常好用 $.ajaxSetup({ type:'post', dataType:'json' ...

  8. D. Lakes in Berland (DFS或者BFS +连通块

    https://blog.csdn.net/guhaiteng/article/details/52730373 参考题解 http://codeforces.com/contest/723/prob ...

  9. BCB 编写服务程序的一个注意事项

      BCB编写服务,install报错的一个问题 今天编写了一个服务,最后INSTALL 的时候报错,如图: 经过近1小时的比较(俺过去写例子),居然无意中设置了一个属性               ...

  10. 【C++/html版 代码 : 暴力破解数字红包 】-- 只要有编译器或者,不看运气,用手速敲代码说话,多人合作效果更佳!

    需求分析: 或者是更大的范围! 是不是很捉急!运气背点不就over了! C++版: #include <stdio.h> #include <stdlib.h> #includ ...