背景

虽然大家都已经使用了统一的关键字,但是在检查了一些测试用例之后,还是发现因为大家对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. JS中的原型对象与构造器

    在Javascript中:原型对象是属于构造函数的,不属于实例:实例只能共享原型对象中的属性和方法(当然也可以有自己的属性和方法,或者覆盖原型中同名的属性和方法):构造器constructor属于原型 ...

  2. VS code C++代码没有自动提示

    用了一段时间的VS code,发现一直都没有代码提示,奇了个怪?可能是插件有问题,于是重装C/C++,clang...等插件.结果......没用,

  3. Spring中Bean的管理问题

    首先,配置文件中定义的bean并不是都在启动时实例化. <bean id="accountService" class="com.foo.DefaultAccoun ...

  4. 浅谈JAVA继承关系中的构造函数

    话不多说直接上例子,我的例子中定义了两个类,TheSon和TheFather,TheSon继承了TheFather,如图: TheSon类的定义: ​ TheFather类的定义: 当我们初始化The ...

  5. HCIP DAY2

    OSPF协议的基本特点: 支持无类域间路由(CIDR) vlsm NA 无路由自环 收敛速度快 使用IP组播放收发协议数据 支持多条等值路由 静态路由 动态路由 等价路由 浮动路由 支持协议报文的认证 ...

  6. AWD模式搅屎模式

    AWD模式搅屎模式 ###0x01 出题思路 ####1:题目类型 1-出题人自己写的cms,为了恶心然后加个so. 2-常见或者不常见的cms. 3-一些框架漏洞,比如ph师傅挖的CI这种 #### ...

  7. [Mac][Python][Jupyter Notebook]安装配置和使用

    Jupyter 项目(以前称为 IPython 项目),提供了一套使用功能强大的交互式 shell 进行科学计算的工具,实现了将代码执行与创建实时计算文档相结合. 这些 Notebook 文件可以包含 ...

  8. [Docker][Hadoop]基于Docker1.12.3 搭建Hadoop 2.7.2 集群以及简单分析

    一 Hadoop简介 Hadoop 2.7.2 Doc refer to http://hadoop.apache.org/docs/r2.7.2/ HDFS (The following is a ...

  9. markdown在typora的超方便的应用

    经常性需要进行文字的编写,但是使用word比较麻烦,而excel又不方便自己的工作实际实用,特此有一款软件支持我的应用,typora软件,让人使用的无法自拨. typora是基于markdown的来应 ...

  10. js面向对象篇(一)

    Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类). ----摘 ...