写在前面

RF自动化的文章记录基本完成,建一个汇总目录,方便查看。

【Robot Framework 项目实战】汇总

∮【RF 项目实战 00】环境搭建

∮【RF 项目实战 01】使用 RequestsLibrary 进行接口测试

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

∮【RF 项目实战 03】使用脚本自动生成统一格式的RF自动化用例

∮【RF 项目实战 04】基于录制生成RF关键字及基础自动化用例

脚本优化

上一篇博客我们编写了基于录制生成的RF自动化Demo用例,但是只是完全根据抓包数据构造了一条正常的测试用例,其实针对接口的参数校验这样的重复性比较强的测试,我们也可以把它们脚本化,参数化到RF文件中。

接口测试,基本参数校验范围

基本参数校验,是每次接口测试首要考虑的内容,这部分应当是测试工程师的基本能力。

  1. 可选与必选

    • 字段可选,传与不传时的区别
    • 字段必选,必选参数缺失时返回什么错误,返回格式是否标准
  • 空值

    • 空值时,返回什么结果。(如网络超时未返回,当成空值在处理还是默认值处理)
  • 默认值
    • 是否有默认值,可选参数和必选参数是否有默认值
  • 类型
    • int,区分32和64位,int类型时,传str时的错误展示
    • string类型,
    • float类型,往往在计算金额时,会用到浮点数
  • 类型长度
    • 超过长度,接口请求是否出错,如果不出错,展示是否被截断
    • 中文跨越边界时被截断的问题,如nickname是32字节,共16个中文,前15是中文,第16是英文,第17是中文,则多出一个字节,最后一个中文是否被截断显示为乱码
  • 大小写
    • 是否大小写敏感,signkey,等内容,一般大小写敏感
  • 安全过滤
    • <>是否被过滤掉,是否有直接存写到DB
    • ' " 是否被转译或者使用防SQL注入的ORM组件
  • 编码类型
    • utf-8,GBK,unicode
    • 特殊字符(空格,换行等),emoji(4个字节),中文,拉丁文,日文等

具体实现

首先我们定义一批可能需要传递的参数,使用常量的方式存储。

PARAM_ERR = 10000
OK = 0
BOOL = True # False
INT = 10
NEG_INT = -1
ZERO = 0
BIG_INT = 99**5
NEG_FLOAT = -1.1
FLOAT = 0.99
EMPTY_STR = ""
INT_STR = "1111"
LETTERS_STR = "ABCabc"
SPACE_STR = " "
EMPTY_LIST = []
STR_LIST = ["a", "b"]
INT_LIST = [10, 20]
BOOL_LIST = [True, False]
MIX_LIST = ["a", True, 10, ["aa"], {"a": "aa"}]
EMPTY_DICT = {}
STR_DICT = {"a": "b"}
INT_DICT = {"d": 11}
BOOL_DICT = {"c": True}
MIX_DICT = {"b": "", "c": True, "d": 11, "e": {"f": [1, 2]}}
...

然后我们通过原始的请求参数,自己组装不同的请求参数:

def gen_req_data(sheet_obj):
str_params = sheet_obj.cell_value(1, 1)
str_method = sheet_obj.cell_value(1, 6)
temp_list = []
# print(f"str_params:{str_params}")
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 = "" # 正常参数
temp_list.append(params) # 添加异常参数
for k, v in params.items():
if isinstance(v, dict):
for i in [
BOOL,
NEG_FLOAT,
LETTERS_STR,
MIX_LIST,
ZERO,
MIX_DICT
]:
params = copy.deepcopy(params) # 深拷贝,字典存储的是内存地址
params[k] = i # doc
temp_list.append(params)
elif isinstance(v, list):
for i in [BOOL, NEG_FLOAT, LETTERS_STR, MIX_LIST, ZERO, MIX_DICT]:
params = copy.deepcopy(params)
params[k] = i
temp_list.append(params)
elif isinstance(v, str):
for i in [BOOL, NEG_FLOAT, EMPTY_STR, INT_STR, SPACE_STR, MIX_DICT, STR_LIST, EMPTY_DICT]:
params = copy.deepcopy(params)
params[k] = i
temp_list.append(params)
elif isinstance(v, int):
for i in [BOOL, NEG_FLOAT, INT_STR, INT_LIST, NEG_INT, ZERO, BIG_INT, NEG_FLOAT, FLOAT, EMPTY_DICT]:
params = copy.deepcopy(params)
params[k] = i
temp_list.append(params)
elif isinstance(v, bool):
for i in [True, False, ZERO, FLOAT, NEG_INT, INT_STR, INT_LIST, STR_DICT]:
params = copy.deepcopy(params)
params[k] = i
temp_list.append(params)
return str_method, temp_list

最后,我们把不同的请求参数转化为RF测试用例需要的数据格式,最终生成对应的测试用例:

def gen_testcase(self, sheet_obj, target_robot_name, interface_name):
"""
:param sheet_obj:
:param target_robot_name:
:param interface_name:
:return:
"""
method, params_list = self.gen_req_data(sheet_obj)
with open(target_robot_name, 'a') as f:
for num, param in enumerate(params_list):
"""
待办:动态修改Documentation的信息,异常参数以tuple的形式存储Documentation,然后解析的时候参数化到文档中
"""
f.write(interface_name + f'.Demo_case{num}' + '\n')
f.write(' [Documentation] demo' + '\n')
f.write(' [Tags] ' + self.tag + '\n')
params = self._gen_param_data(method, param)
f.write(params)
if params:
f.write(' ${{Resp_data}} {}'.format(self.project_abbr) + interface_name + ' ${HOST} ' + "${param}")
else:
f.write(' # 未获取到请求参数数据 \n')
f.write(' ${{Resp_data}} {}'.format(self.project_abbr) + interface_name + ' ${HOST} ' + "${EMPTY}")
f.write('\n')
f.write(' Log ${Resp_data.text}' + '\n') # 第一条用例正常断言,其他用例标记为失败用例
if num == 0:
f.write(' Should Be Equal As Strings ${Resp_data.status_code} 200' + '\n')
f.write(' ${resp_json} to json ${Resp_data.text}' + '\n')
f.write(self.gen_exp_data(sheet_obj))
else:
f.write(f' Should Be Equal As Strings ${{Resp_data.status_code}} {self.error_status_code}' + '\n')
f.write(' ${resp_json} to json ${Resp_data.text}' + '\n')
f.write(self._format_exp_data(self.param_error_json)) # param_error_json 接口异常返回内容中的公共部分,比如code, result
f.write('\n')
logger.info("Demo case保存于:" + target_robot_name)

:⚠️ 部分依赖代码在上一篇文章中可以找到。

总结

通过抓包,我们获取了原始数据,然后根据抽象异常参数传递校验的方式,把接口测试异常用例抽取了出来,这个不管是在手工测试过程中,还是在自动化过程中都非常的有用,能节省大量的人力成本。

当然这个方式也有一定的局限性,需要整个团队来配置,比如脚本中使用到的param_error_json就是因为博主所在项目组有比较规范的接口返回定义才能做这样的统一断言。

【Robot Framework 】项目实战汇总的更多相关文章

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

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

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

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

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

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

  4. 【Robot Framework 项目实战 03】使用脚本自动生成统一格式的RF自动化用例

    背景 虽然大家都已经使用了统一的关键字,但是在检查了一些测试用例之后,还是发现因为大家对RF的熟悉程度不一导致的测试用例颗粒度差异很大的情况:而且在手动方式转化测试用例过程中,有不少工作是完全重复的且 ...

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

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

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

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

  7. Robot Framework 项目搭建

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

  8. Robot Framework 学习资源汇总

    学习网站 http://robotframework.org/ http://www.testtao.cn/?cat=43 https://www.jianshu.com/c/483e8ffcbc79 ...

  9. 自动化测试框架Cucumber和Robot Framework的实战对比

    自动化测试框架Cucumber和RobotFramework的实战对比 一.摘要 自动化测试可以快速自动完成大量测试用例,节约巨大的人工测试成本:同时它需要拥有专业开发技能的人才能完成开发,且需要大量 ...

随机推荐

  1. python学习之掷骰子游戏

    """ 通过学习的python知识,写一个简单的python小游戏 游戏名字:掷骰子比大小 游戏规则: 1.玩家可以选择玩掷几个骰子游戏(默认3个) 2.玩家可以设置双方 ...

  2. React/事件系统

    React基于虚拟DOM实现了一个合成事件层,我们所定义的事件处理器会接收到一个合成事件对象的实例事件处理. 并且所有事件都自动绑定在最外层上.如果需要访问原生事件对象,可以使用nativeEvent ...

  3. 使用element-ui中的el-upload组件时携带其他参数

    解决方法:// template <el-upload action="/api/oss/file/add" :headers="headers" // ...

  4. S2-045、S2-046

    前言 S2-045依然是一个Ognl表达式注入导致的RCE漏洞,且漏洞很严重.另外,还是建议读者阅读本篇文章前先看下系列文章的第一篇. 正文 依然是第一篇文章中讲过,StrutsPrepareFilt ...

  5. Masonry个人笔记

    1.有些场合需要获取View在约束之后的frame.直接init初始化后取出来的均为(0,0,0,0).在以下方法中获取即可: View: - (void)layoutSubviews ViewCon ...

  6. Array + two points leetcode.15-3Sum

    题面 Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Fi ...

  7. ASE19团队项目 beta阶段 model组 scrum1 记录

    本次会议于12月2日,18时30分在微软北京西二号楼sky garden召开,持续25分钟. 与会人员:Jiyan He, Kun Yan, Lei Chai, Linfeng Qi, Xueqing ...

  8. 网络OSI 7层模型

    OSI 的英文全程为Open Systems Interconnection ,中文全程为开放系统互联参考模型.是一个逻辑上的定义.主要用途使通信和计算系统自由互联,而不依赖其他架构或技.主要目标就是 ...

  9. 一:(1.1)了解MVC之路由重写

    Mvc默认路由 //系统的Url路由规则 routes.MapRoute( name: "Default", url: "{controller}/{action}/{i ...

  10. mongodb索引 单键索引

    单键索引是最普通的索引,比如一条记录,形式为{x:1,y:2,z:3},我们在x上建立索引,之后就可以以x为条件进行查询,与_id索引不同,单键索引不会自动创建 创建索引 > db.test2. ...