背景

虽然大家都已经使用了统一的关键字,但是在检查了一些测试用例之后,还是发现因为大家对RF的熟悉程度不一导致的测试用例颗粒度差异很大的情况;而且在手动方式转化测试用例过程中,有不少工作是完全重复的且意义不大的,所以我就想了一个使用脚本生成自动化测试用例的方式来解决这个问题。

实现思路

前一篇文章里提到过,我们使用了一个中间的Excel来生成关键字信息,所以我这边的第一想法就是让这个Excel发挥更大的作用 -- 即直接通过Excel生成标准的测试用例。

具体的思路也很简单:

  • 直接转化我们填写在Excel中的请求参数与预期结果。

    • 以递归的形式处理多层级的数据,存储到一个列表中,然后倒序写到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自动化用例的更多相关文章

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

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

  2. 【Robot Framework 项目实战 04】基于录制,生成RF关键字及 自动化用例

    背景 因为服务的迁移,Jira版本的更新,很多接口文档的维护变少,导致想要编写部分服务的自动化测试变得尤为麻烦,很多服务,尤其是客户端接口需要通过抓包的方式查询参数来编写自动化用例,但是过程中手工重复 ...

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

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

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

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

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

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

  6. mybatis generator配置,Mybatis自动生成文件配置,Mybatis自动生成实体Bean配置

    mybatis generator配置,Mybatis自动生成文件配置,Mybatis自动生成实体Bean配置 ============================== 蕃薯耀 2018年3月14 ...

  7. Vs code自动生成Doxygen格式注释

    前言 ​ 程序中注释的规范和统一性的重要性不言而喻,本文就推荐一种在用vscode编写代码时自动化生成标准化注释格式的方法,关于Doxygen规范及其使用可查看博文 代码注释规范之Doxygen. ​ ...

  8. 【SSH项目实战三】脚本密钥的批量分发与执行

    [SSH项目实战]脚本密钥的批量分发与执行 标签(空格分隔): Linux服务搭建-陈思齐 ---本教学笔记是本人学习和工作生涯中的摘记整理而成,此为初稿(尚有诸多不完善之处),为原创作品,允许转载, ...

  9. Robot Framework 项目搭建

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

随机推荐

  1. springboot启动流程(一)构造SpringApplication实例对象

    所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 启动入口 本文是springboot启动流程的第一篇,涉及的内容是SpringApplicat ...

  2. Android Service的有关总结

    来自一位网友的评论 1.使用方式 startService 启动的服务 主要用于启动一个服务执行后台任务,不进行通信.停止服务使用stopService bindService 启动的服务 该方法启动 ...

  3. java实现当前时间往前推N小时

    import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date; /** * @author sha ...

  4. linux:# vi /etc/profile -bash: vi: command not found 的解决办法

    /bin/vi /etc/profile 直接用全路径vi,linux下一切皆文件,进去把profile文件内容改一下,一定是profile出了问题 export JAVA_HOME=/usr/jav ...

  5. 一线互联网常见的Java面试题,你颤抖了吗程序员

    跳槽不算频繁,但参加过不少面试(电话面试.face to face面试),面过大/小公司.互联网/传统软件公司,面糊过(眼高手低,缺乏实战经验,挂掉),也面过人,所幸未因失败而气馁,在此过程中不断查缺 ...

  6. TightVNC安装

    软件版本:tightvnc-2.8.8-gpl-setup-64bit.msi 后面一路默认,虚拟机端口默认从5900开始递增.

  7. 初级文件IO——IO过程、open、close、write、read、lseek、dup、dup2、errno、perror

    先要回答的问题 文件IO指的是什么? 本文主要讲述如何调用Linux OS所提供的相关的OS API,实现文件的读写. 如何理解文件IO? IO就是input output的意思,文件io就是文件输入 ...

  8. pynq系列__LED灯闪烁

    1.实现在board项中自动配置pynq-z2开发板 (1).board file下载地址:http://www.tul.com.tw/ProductsPYNQ-Z2.html   (2).下载之后得 ...

  9. 算法笔记--可撤销并查集 && 可持久化并查集

    可撤销并查集模板: struct UFS { stack<pair<int*, int>> stk; int fa[N], rnk[N]; inline void init(i ...

  10. 0001SpringBoot整合Mybatis

    SpringBoot整合Mybatis主要分为以下几个步骤: 1.添加Mybatis的起步依赖(pom.xml) 2.添加数据库驱动坐标(pom.xml) 3.添加数据库连接信息(applicatio ...