背景

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

最新文章

  1. 关于iOS后台问题( 一 )(ios后台刷新,后台定位,后台下载,真后台)
  2. 可在广域网部署运行的QQ高仿版 -- GGTalk总览
  3. OkHttp,Retrofit 1.x - 2.x 基本使用
  4. css绘制特殊图形基础
  5. linux:主机规划和磁盘分割
  6. if else 语句练习
  7. [分享·JavaScript]提取Table中的内容到XML对象
  8. Thinkphp框架----微信公众测试号开发
  9. Hadoop文件系统常用命令
  10. Solr使用初探——Solr的安装环境与配置
  11. 使用FileSystemWatcher监视文件变化
  12. python学习笔记之十:文件和素材
  13. 【stanford C++】字符串(String)与流(Stream)
  14. bootstarp模板02
  15. gym 101858
  16. Django2.0资料
  17. Singer 学习二 使用Singer进行gitlab 2 postgres 数据转换
  18. webstorm “Unterminated statement”
  19. Windows Phone本地数据库(SQLCE):5、[Association]attribute(翻译)(转)
  20. OK6410 rmmod卸载模块失败:No such file or directory -- 转

热门文章

  1. Snort Inline IPS Mode
  2. Unity 宽度适配 NGUI
  3. 谷歌浏览器chrome安装vue-devtools 插件
  4. 用python在屏幕上输出一个杨辉三角
  5. Scyther攻击输出图的解释(之二)
  6. page页面403
  7. Oracle 安装步骤
  8. Spring的使用及Spring3.2控制器增强@ControllerAdvice
  9. serializers--嵌套关系作为字段来表示
  10. 关于webpack require.context() 的那点事