【Robot Framework 项目实战 04】基于录制,生成RF关键字及 自动化用例
背景
因为服务的迁移,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关键字及 自动化用例的更多相关文章
- 【Robot Framework 项目实战 03】使用脚本自动生成统一格式的RF自动化用例
背景 虽然大家都已经使用了统一的关键字,但是在检查了一些测试用例之后,还是发现因为大家对RF的熟悉程度不一导致的测试用例颗粒度差异很大的情况:而且在手动方式转化测试用例过程中,有不少工作是完全重复的且 ...
- 【Golang】基于录制,自动生成go test接口自动化用例
背景 之前写过一篇博客,介绍怎么用Python通过解析抓包数据,完成自动化用例的编写.最近这段时间在使用go test,所以就在想能不能也使用代码来生成自动化用例,快速提升测试用例覆盖率.说干就干. ...
- 【Robot Framework 项目实战 02】使用脚本生成统一格式的RF关键字
背景 在微服务化的调用环境下,测试数据及接口依赖的维护是一个问题,因为依赖的接口和数据可能不在同一个服务下,而这相关的多个服务往往是不同人员来测试的. 因此为了节省沟通成本,避免关键字的重复冗余.所以 ...
- 【Robot Framework 项目实战 01】使用 RequestsLibrary 进行接口测试
写在前面 本文我们一起来学习如何使用Robot Framework 的RequestsLibrary库,涉及POST.GET接口测试,RF用例分层封装设计等内容. 接口 接口测试是我们最常见的测试类型 ...
- 【Robot Framework 项目实战 00】环境搭建
前言 我们公司在推广RF这个框架做后端接口测试,力求让同事们能更快的完成服务端需求的自动化,作为主导者之一,决定分享一些经验,方便后来者. 我会从安装部署.Request.selenium.自定义框架 ...
- 【Robot Framework 项目实战 02】SeleniumLibrary Web UI 自动化
前言 SeleniumLibrary 是针对 Robot Framework 开发的 Selenium 库.它也 Robot Framework 下面最流程的库之一.主要用于编写 Web UI 自动化 ...
- 自动化测试框架Cucumber和Robot Framework的实战对比
自动化测试框架Cucumber和RobotFramework的实战对比 一.摘要 自动化测试可以快速自动完成大量测试用例,节约巨大的人工测试成本:同时它需要拥有专业开发技能的人才能完成开发,且需要大量 ...
- SDKStyle的Framework项目使用旧版项目文件生成的Nuget包遇到的问题
随笔-2021-11-10 SDKStyle的Framework项目使用旧版项目文件生成的Nuget包遇到的问题 简介 C#从NetCore之后使用了新版的项目文件,SDK-Style项目,新版本的项 ...
- Robot Framework 项目搭建
首先新建一个项目“RobotDemo".项目Type一般选择“Directory”形式. 项目第一层可以放3种文件:Test Suite.Directory 和 Resource File. ...
随机推荐
- C#使用Selenium网页自动化
工作中很多时候经常需要网抓数据或者把数据填写到网站上,使用Selenium将其自动化是一种不错的选择.Selenium其实是一个用于Web应用程序测试的工具,测试你的应用程序看是否能够很好地工作在不同 ...
- 一次腾讯云centos服务器被入侵的处理
昨天一大早,我还没到公司呢,就收到腾讯云安全中心发来的服务器异常登录告警,登录控制台一看,ip还是美国的,一脸懵逼.由于本人之前也没有过处理服务器入侵的经验,而且这台服务器目前还没有部署商用系统,所以 ...
- 括号配对检测 A
括号配对检测 A ...
- 原生js上传图片遇到的坑(axios封装)
后台给我写了一个上传图片的接口,自己用form表单测试成功 接口可以正常跳转 测试的代码: <!doctype html> <html lang="en"> ...
- spring 实现事务配置的方式
spring 中常用的两种事务配置方式以及事务的传播性.隔离级别 一.注解式事务 1.注解式事务在平时的开发中使用的挺多,工作的两个公司中看到很多项目使用了这种方式,下面看看具体的配置demo. 2. ...
- python多线程与多进程异步事件框架
多线程简单实现 #!/usr/bin/env python # -*- coding: UTF-8 -*- import logging import queue import threading f ...
- 栈 · 有getMin功能的栈O(1)
题面 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中的最小元素的操作. 要求 pop(), push(), getMin()时间复杂度都是O(1) 思路 1.准备两个栈,数据栈+最小元素 ...
- 让你在上司眼里“更靠谱”的六个建议
"勇于创新"是职场一大谎言 晋升选择题 你有两个下属,你想从他们中挑一个升职,你觉得哪一个更适合? 员工A: 优点:奉行"80%的精力维护20%的重要客户"的原 ...
- CentOS7安装CDH 第四章:CDH的版本选择和安装方式
相关文章链接 CentOS7安装CDH 第一章:CentOS7系统安装 CentOS7安装CDH 第二章:CentOS7各个软件安装和启动 CentOS7安装CDH 第三章:CDH中的问题和解决方法 ...
- SVN 执行cleanup报错:Cleanup failed to process the following paths
SVN 执行cleanup报错:Cleanup failed to process the following paths 先来说下这个错误的原因:用SVN在使用过程中,各种原因中途取消或中断,导致需 ...