【Robot Framework 项目实战 03】使用脚本自动生成统一格式的RF自动化用例
背景
虽然大家都已经使用了统一的关键字,但是在检查了一些测试用例之后,还是发现因为大家对RF的熟悉程度不一导致的测试用例颗粒度差异很大的情况;而且在手动方式转化测试用例过程中,有不少工作是完全重复的且意义不大的,所以我就想了一个使用脚本生成自动化测试用例的方式来解决这个问题。
实现思路
前一篇文章里提到过,我们使用了一个中间的Excel来生成关键字信息,所以我这边的第一想法就是让这个Excel发挥更大的作用 -- 即直接通过Excel生成标准的测试用例。
具体的思路也很简单:
- 直接转化我们填写在Excel中的请求参数与预期结果。
- 以递归的形式处理多层级的数据,存储到一个列表中,然后倒序写到robot文件中
最关键的代码如下:
- 以递归的形式处理多层级的数据,存储到一个列表中,然后倒序写到robot文件中
发送数据转化
请求的数据如下:
{
"name": "Detector",
"age": 18,
"sex": "male",
"student": false,
"others": [{"nation": "CHINA"}]
}
我们需要对数据逐层进行解析,然后生成下面的这个数据)。
${others} create dictionary nation=CHINA
${others_list} create list ${others}
${param} create dictionary name=Detector age=${18} sex=male student=${False} others=${others_list}
注: RF脚本中所有的非特殊标示的数据皆为string,bool类型及int类型需要用${something}包裹
因为请求数据是逐行执行,所以所有的参数定义都需要逐行进行赋值,受限于RF的语法,这一块花了不少时间,最后使用两个函数相互递归的方式解决。
_format_list用于处理list, _format_dict用于处理dict, temp_list用于存储生成的关键字信息,最后使用'\n'.join(temp_list) + "\n"把所有的子关键字组装成RF关键字代码。
相关代码:
代码目录结构如下:

def _gen_param_data(self, sheet_obj, param_key="param"):
"""
获取Excel中发送参数的数据
:param sheet_obj:
:param param_key:
:return:
"""
str_params = sheet_obj.cell_value(1, 1)
str_method = sheet_obj.cell_value(1, 6)
if not len(str_params):
return ""
try:
# 转化 json类型为Python标准类型
params = eval(str_params.replace("false", "False").replace("true", "True").replace("null", "None"))
if not len(params):
return ""
except Exception as f:
logger.warning("====================================================")
logger.error("=" + str(f))
logger.warning("====================================================")
params = ""
if str_method.upper() == "GET":
# 格式化get请求
format_str = self.format_get_params(params, param_key)
else:
# 格式化post请求
format_str = self.format_post_params(params)
return format_str
def format_post_params(self, params):
"""
格式化post请求传递数据
:param params:
:return:
"""
temp = []
# 格式化数据
if isinstance(params, dict):
self._format_dict(params, "param", temp)
temp.reverse()
if isinstance(params, list):
print("list")
self._format_list(params, "param", temp)
temp.reverse()
return '\n'.join(temp) + "\n"
def _format_list(self, _list, key_word, temp_list):
tem_str = " ${%s_list} create list " % key_word
if len(_list) > 0 and isinstance(_list, list):
for i in _list:
if isinstance(i, dict):
tem_str = " ${%s_list} create list ${%s}" % (key_word, key_word)
self._format_dict(i, key_word, temp_list)
elif isinstance(i, list):
self._format_list(i, key_word, temp_list)
else:
tem_str += self.format_bool_int(i) + " "
temp_list.insert(0, tem_str)
def _format_dict(self, _dict, key_word, temp_list):
tem_str = " ${%s} create dictionary " % key_word
if len(_dict) > 0 and isinstance(_dict, dict):
for k, v in _dict.items():
v = self.format_bool_int(v)
if isinstance(v, str):
tem_str += k + "=" + v + " "
if isinstance(v, dict):
tem_str += k + "=" + "${%s_dict} " % k
self._format_dict(v, "%s_dict" % k, temp_list)
if isinstance(v, list):
tem_str += k + "=" + "${%s_list} " % k
self._format_list(v, k, temp_list)
temp_list.insert(0, tem_str)
def format_get_params(params, param_key):
"""
格式化get请求传递数据
:param params:
:param param_key:
:return:
"""
format_str = " ${%s} set variable ?" % param_key
if isinstance(params, dict):
for k, v in params.items():
if isinstance(v, int) or isinstance(v, bool):
v = "${%s}" % v
format_str = format_str + str(k) + "=" + str(v) + "&"
if isinstance(params, list):
pass # 后续完善
return format_str.strip("&") + '\n'
用例初始化
首先,我们把每条用的引用数据写到文件中。其中/env/env.robot用于存放我们的配置文件。
def gen_testcase_init(target_robot_name):
"""
测试用例初始化内容
:param target_robot_name:
:return:
"""
if os.path.exists(target_robot_name):
os.remove(target_robot_name)
with open(target_robot_name, 'a') as f:
f.write('*** Settings ***' + '\n')
f.write('Documentation documentation' + '\n')
f.write('Suite Setup Setup func' + '\n')
f.write('Suite Teardown Teardown func' + '\n')
f.write('Test Setup log Test Setup' + '\n')
f.write('Test Teardown log Teardown' + '\n')
f.write('Resource ../../../Common/DT_Hb_kw/DT_Hb_kwRequests.robot' + '\n')
f.write('Resource ./env/env.robot' + '\n')
# f.write('Library TestLibrary' + '\n')
f.write('\n')
f.write('*** Variables ***' + '\n')
f.write('${OK} OK' + '\n')
f.write('\n')
f.write('*** Test Cases ***' + '\n')
前置条件及数据清理
def gen_end_keyword(target_robot_name):
"""
测试用例初始化内容
:param target_robot_name:
:return:
"""
with open(target_robot_name, 'a') as f:
f.write('*** Keywords ***' + '\n')
f.write('Setup func' + '\n')
f.write(' log setup func' + '\n')
f.write('Teardown func' + '\n')
f.write(' log teardown func' + '\n')
f.write('\n')
apitest/
├── Common
│ ├── DT_Hb_kw # 公共RF关键字存储目录
│ │ └── DT_Hb_kwRequests.robot
│ ├── DT_Hb_kw_excel # 公共过程Excel存储目录
│ │ ├── detector.xls
│ │ ├── detector_Get.xls
│ │ ├── detector_getBingo.xls
│ │ ├── detector_post.xls
│ │ └── detector_postName.xls
│ └── Testscript # 辅助脚本存储目录
│ ├── DT_Hb_kwRequests.robot
│ ├── common
│ │ ├── __init__.py
│ │ ├── gen_rf_demo_case.py
│ │ ├── gen_rf_kw.py
│ │ ├── gen_testcase.py
│ │ ├── har_parse.py
│ ├── common_testcase # 普通用例存储目录
│ │ └──
│ ├── display
│ │ ├── client.py
│ │ ├── ipsitter.xls
│ │ └── server.py
│ ├── har_files # har文件存储目录
│ │ └── 20190812-Demo.har
│ ├── logs
│ │ └── 2019-08-16.log
│ ├── rf_demo_cases # 生成的自动化用例存储
│ ├── run.py
│ ├── source_xls
│ │ ├── new_keyword_excel # 用于生成关键字的Excel存储目录
│ │ └── templates # 模板Excel存储目录
│ │ ├── case_template.xls
│ │ └── kw_template.xls
│ └── utils
│ ├── __init__.py
│ ├── logger.py
│ └── operate_xls.py
├── Testcase
│ ├── DT_Hb_case
│ │ ├── Demo_server # 测试用例提交处
│ │ ├── Post_Demo # 测试用例提交处
│ │ └── _common # 项目公共关键字存储目录
│ │ ├── commonFun.robot
│ │ ├── common_func.py
│ │ └── env.robot
【Robot Framework 项目实战 03】使用脚本自动生成统一格式的RF自动化用例的更多相关文章
- 【Robot Framework 项目实战 01】使用 RequestsLibrary 进行接口测试
写在前面 本文我们一起来学习如何使用Robot Framework 的RequestsLibrary库,涉及POST.GET接口测试,RF用例分层封装设计等内容. 接口 接口测试是我们最常见的测试类型 ...
- 【Robot Framework 项目实战 04】基于录制,生成RF关键字及 自动化用例
背景 因为服务的迁移,Jira版本的更新,很多接口文档的维护变少,导致想要编写部分服务的自动化测试变得尤为麻烦,很多服务,尤其是客户端接口需要通过抓包的方式查询参数来编写自动化用例,但是过程中手工重复 ...
- 【Robot Framework 项目实战 00】环境搭建
前言 我们公司在推广RF这个框架做后端接口测试,力求让同事们能更快的完成服务端需求的自动化,作为主导者之一,决定分享一些经验,方便后来者. 我会从安装部署.Request.selenium.自定义框架 ...
- 【Robot Framework 项目实战 02】SeleniumLibrary Web UI 自动化
前言 SeleniumLibrary 是针对 Robot Framework 开发的 Selenium 库.它也 Robot Framework 下面最流程的库之一.主要用于编写 Web UI 自动化 ...
- 【Robot Framework 项目实战 02】使用脚本生成统一格式的RF关键字
背景 在微服务化的调用环境下,测试数据及接口依赖的维护是一个问题,因为依赖的接口和数据可能不在同一个服务下,而这相关的多个服务往往是不同人员来测试的. 因此为了节省沟通成本,避免关键字的重复冗余.所以 ...
- mybatis generator配置,Mybatis自动生成文件配置,Mybatis自动生成实体Bean配置
mybatis generator配置,Mybatis自动生成文件配置,Mybatis自动生成实体Bean配置 ============================== 蕃薯耀 2018年3月14 ...
- Vs code自动生成Doxygen格式注释
前言 程序中注释的规范和统一性的重要性不言而喻,本文就推荐一种在用vscode编写代码时自动化生成标准化注释格式的方法,关于Doxygen规范及其使用可查看博文 代码注释规范之Doxygen. ...
- 【SSH项目实战三】脚本密钥的批量分发与执行
[SSH项目实战]脚本密钥的批量分发与执行 标签(空格分隔): Linux服务搭建-陈思齐 ---本教学笔记是本人学习和工作生涯中的摘记整理而成,此为初稿(尚有诸多不完善之处),为原创作品,允许转载, ...
- Robot Framework 项目搭建
首先新建一个项目“RobotDemo".项目Type一般选择“Directory”形式. 项目第一层可以放3种文件:Test Suite.Directory 和 Resource File. ...
随机推荐
- cmd查找端口占用情况
查找端口占用情况:netstat -ano|findstr 4848 查看使用指定端口的应用程序:tasklist|findstr xxxx,xxxx指的是pid 结束指定进程:taskkill /p ...
- 解决ios中input兼容性问题
1.解决input输入框在iOS中有阴影问题 input{ -webkit-appearance: none; } 2.checkbox.raido在ios中阴影问题 单选: ...
- Spark学习笔记2——RDD(上)
目录 Spark学习笔记2--RDD(上) RDD是什么? 例子 创建 RDD 并行化方式 读取外部数据集方式 RDD 操作 转化操作 行动操作 惰性求值 Spark学习笔记2--RDD(上) 笔记摘 ...
- zabbix初级进阶
目录 一.理论概述 zabbix功用 运行条件 缺点 zabbix组件 部署 web安装zabbix 优化 总结 这篇文章主要对zabbix有一个全面且简单的了解 一.理论概述 zabbix功用 检测 ...
- 【转】PS1应用-修改linux终端命令行字体颜色
原文链接:https://www.jianshu.com/p/4239d3ea72fe cd ls -la vim .bashrc 在.bashrc中加入这一行: PS1="\[\e[37; ...
- Install RabbitMQ on CentOS 7
NOTE: this article is only for CentOS 7 How to Install RabbitMQ on CentOS 7 yum update Install erlan ...
- selenium 显示等待wait.until 常用封装 及下拉框的选择操作等
from selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWait a ...
- GPU显存释放
一.当程序没有运行,但GPU仍被占用, 可通过nvidia-smi查看,被占用的pid是什么 或通过sudo fuser -v /dev/nvidia* #查找占用GPU资源的PID 然后采用kill ...
- sklearn线性回归实现房价预测模型
目录 题目要求 单特征线性回归 方案一 方案二 多特征线性回归 两份数据 ex1data1.txt ex1data2.txt 题目要求 建立房价预测模型:利用ex1data1.txt(单特征)和ex1 ...
- 2018/7/31-zznu-oj- 2128: 素数检测 -【费马小定理裸应用】
2128: 素数检测 时间限制: 1 Sec 内存限制: 128 MB提交: 84 解决: 32[提交] [状态] [讨论版] [命题人:admin] 题目描述 在算法竞赛中你会遇到各种各样的有关 ...