接口自动化测试

  • 简介
  • 接口用例设计
  • Excel的操作
  • 接口框架设计

简介

本文档介绍如何使用excel管理接口测试用例并一键执行的实现方式,其中包括 python 读写excel, request库的基本操作,接口用例的设计
源码下载传送门>>APIAtuoTest

接口用例设计


用例字段描述

  • 被依赖表达式: 示例 (3,headers,data,response,file),第一位填写被依赖用例id,若依赖多条数据则可在后加(headers,data,response,file),字段之间使用英文"逗号"隔开,加入 headers 则表示 用例id为 3 的用例需要本条用例的 headers 数据,其它以此类推. 填写了 被依赖表达式,本条用例执行完成会自动根据 被依赖表达式 组装本条用例数据写入到被依赖用例的 需要依赖数据 中
# 组装本条用例后的数据
data = {'data': {'ip': '112.112.11.11', 'key': 'key'},'response': {'resultcode': '200','reason': '查询成功','result': {'Country': '中国', 'Province': '云南省', 'City': '昆明市', 'Isp': '电信'},'error_code': 0},'file': 'timg.txt'}
  • 需依赖表达式: 例如取值上方 data 中的 ip 和 key 数据,则表达示例为(var_ip=data.ip,var_key=data.key),var_ip 是变量名称, data.ip 则是数据所在的路径, 多层 dict 则通过 英文"点"把key相连,最终取到数据,若需取值多个值,则每个值之间使用英文"逗号"隔开. 取值成功后会自动写入到本条用例的 需依赖数据取值结果中
# 取值表达式
var_ip=data.ip,var_key=data.key
# 被取值数据
data = {'data': {'ip': '112.112.11.11', 'key': 'key'},'response': {'resultcode': '200','reason': '查询成功','result': {'Country': '中国', 'Province': '云南省', 'City': '昆明市', 'Isp': '电信'},'error_code': 0},'file': 'timg.txt'}
# 取值结果
{'var_ip': '112.112.11.11', 'var_key': 'key'}
  • 检查表达式: 目前支持 equal,notequal,in,notin 判断,若需其它判断可自行添加,此表达式分为(resultcode equal 200) 三个部分, 左侧部分为 取值表达式,中间为 判断方式 ,右侧为预期结果,左侧填写的取值表达式会自动去检查数据中把数据匹配出来, 实际就是 200 == 200,若需多个检查点则每个检查点之间使用英文"逗号"隔开.
# 检查表达式
resultcode equal 200,result.Isp equal 电信
# 检查数据
{"resultcode":"200","reason":"查询成功","result":{"Country":"中国","Province":"云南省","City":"昆明市","Isp":"电信"},"error_code":0}
# 检查结果
检查点>实际结果:200等于预期结果:200 pass
检查点>实际结果:电信等于预期结果:电信 pass 

接口用例含有字段及描述
编号 : int(唯一) 用例id
模块 : str 用例所属模块描述,例如 用户管理之类的一级功能
标题 : str 用例简单描述,例如 新增用户之类的二级功能
测试点 : str 用例测试功能,例如 正确用户数据正常新增用户成功
级别 : str 用例重要程度,范围有(P0,P1,P2,P3),这里依照公司对用例级别的划分
执行顺序 : int(唯一) 这里可以设置用例的执行顺序, 1 为最优先执行,上不封顶
是否执行 : str 用例是否需要执行,范围有(Y,y,N,n),大Y小y代表该条用例需要执行,空或者其它都代表不执行
被依赖用例 : str 本条用例是否被其它用例依赖了测试数据
需依赖数据 : str 本条用例需要依赖的数据
依赖数据取值表达式 : str 用例执行会根据此表达式,自动去匹配 需依赖数据中的内容
依赖数据取值结果 : str 根据需依赖数据取值表达式 取值后自动存入,存入示例 {‘var_ip’: ‘112.112.11.11’, ‘var_key’: ‘key’}
接口地址 : str 接口地址
请求头 : str 请求头
请求方式 : get,post,若需要其它可自行添加
请求数据 : str 请求数据
文件名称 : str 此处添加测试框架中 test_data 目录下的 文件全名,若是批量文件上传接口,则可以录入多个文件全名以英文"逗号"隔开
返回结果 : str 用例执行后的返回
检查点 : str 根据 检查表达式 自动匹配 返回结果中的数据,并把检查结果自动写入 执行结果中
执行结果 : str 检查点匹配后的结果信息,包括每个检查点是否通过 和 若用例中的任何报错信息也会 自动录入
开始时间 : str 用例执行开始时间
结束时间 : str 用例执行结束时间
消耗时间 : str 本条用例执行总共花费时间
执行人 : 用例编写人,这个值可在 setting 文件中配置

Excel的操作

封装关于 python 对excel 的基本操作,包括 返回指定行/每行打印/每列打印/读指定位置/写指定位置/按列读/按列写/按行读/按行写等等,下面放了一些实现操作的类方法

  • 替换数据
    # 替换指定位置的值def replace_data(self, row, cell, data):if self.mode == 1:# print(row,cell,data)self.handle_sheet.write(int(row), int(cell), data)self.handle.save(self.excel_filename)return "修改行 %s 列 %s ,修改数据为 %s" % (str(row), str(cell), str(data))else:print(self.excel_filename + u" 不存在,无法进行操作!!!")return 'error: not file.'# 替换一行def replace_nrows(self, data, nrows_number):if self.mode == 1:for i, item in enumerate(data):self.handle_sheet.write(nrows_number - 1, i, item)self.handle.save(self.excel_filename)return nrows_number, letter(i + 1)else:print(self.excel_filename + u" 不存在,无法进行操作!!!")return 'error: not file.'# 替换一列def replace_ncols(self, data, ncols_number):if self.mode == 1:for i, item in enumerate(data):self.handle_sheet.write(i, ncols_number - 1, item)self.handle.save(self.excel_filename)return i + 1, letter(ncols_number)else:print(self.excel_filename + u" 不存在,无法进行操作!!!")return 'error: not file.'
  • 删除数据
    # 删除全部def del_alldata(self):if self.mode == 1:replace_number = 0for i in range(self.sheet.ncols):for n in range(self.sheet.nrows):self.handle_sheet.write(n, i, '')replace_number += 1self.handle.save(self.excel_filename)return replace_numberelse:print(self.excel_filename + u" 不存在,无法进行操作!!!")return 'error: not file.'# 删除行def del_nrows(self, nrows_number):if self.mode == 1:replace_number = 0for i in range(self.sheet.ncols):self.handle_sheet.write(nrows_number - 1, i, '')replace_number += 1self.handle.save(self.excel_filename)return replace_numberelse:print(self.excel_filename + u" 不存在,无法进行操作!!!")return 'error: not file.'# 删除列def del_ncols(self, ncols_number):if self.mode == 1:replace_number = 0for n in range(self.sheet.nrows):self.handle_sheet.write(n, ncols_number - 1, '')replace_number += 1self.handle.save(self.excel_filename)return replace_numberelse:print(self.excel_filename + u" 不存在,无法进行操作!!!")return 'error: not file.'# 删除某个位置def del_data(self, nrows_number, ncols_number):if self.mode == 1:self.handle_sheet.write(nrows_number + 1, ncols_number + 1, '')self.handle.save(self.excel_filename)return self.sheet.cell(ncols_number + 1, nrows_number + 1).valueelse:print(self.excel_filename + u" 不存在,无法进行操作!!!")return 'error: not file.'# 删除指定数据def del_value(self, data):if self.mode == 1:replace_number = 0for i in range(self.sheet.ncols):for n in range(self.sheet.nrows):if data == self.sheet.cell(n, i).value:self.handle_sheet.write(n, i, '')replace_number += 1self.handle.save(self.excel_filename)return replace_numberelse:print(self.excel_filename + u" 不存在,无法进行操作!!!")return 'error: not file.'
  • 读数据
    # 读取指定位置的数据 return datadef xlsred(self, nrows_number, ncols_number):if self.mode == 1:str = self.sheet.cell(nrows_number, ncols_number).valueprint("read data : ", str)print("Data-ncols: ", nrows_number)print("Data-number: ", ncols_number)return strelse:print(self.excel_filename + u" 不存在,无法进行操作!!!")return 'error: not file.'# 每列打印 return datadef xlsread_allncols(self):if self.mode == 1:data_list = []for i in range(self.sheet.ncols):data = []for n in range(self.sheet.nrows):if self.sheet.cell(n, i).value != '':data.append(self.sheet.cell(n, i).value)data_list.append(data)return data_listelse:print(self.excel_filename + u" 不存在,无法进行操作!!!")return 'error: not file.'

接口框架设计

目前框架功能 : 读写excel用例并自动执行后把本身测试结果写入, 后续自行可以 分析测试结果生成 各种版本的测试报告 和 自行推送测试结果至各个平台,如 Email,企业微信,钉钉,微信,短信,平台机器人查看相关产品的接口文档

框架目录

  • APIAutoTest

    • config

      • settings.py
    • doc
    • lib
      • opt_excel.py
      • opt_expression.py
      • opt_test_data.py
      • request_client.py
    • result
    • test_case
      • TestCase.xls
    • test_data
    • tool
      • my_time.py
    • main.py

使用说明

1.环境 :python 3.x ,需依赖 xlrd xlwt xlutils
2.依照 TestCase.xls 用例格式完成用例接口用例编写
3.python main.py 执行测试

代码片段

# opt_expression.py
def write_rely_case_data(now_case_id, data_str):"""该条用例会被谁依赖并把需要依赖的内容写入被依赖用例的 依赖用例数据 中:param data_str: 依赖表达式  2,headers,data,response,file:param now_case_id: 当前测试用例id:return: 把 被依赖的测试数据 写入 需依赖的用例  依赖用例数据 中"""temp_dict = {}# 如果传入的 依赖用例 为空,则不需要组装 需依赖数据 并 写入需依赖的用例中if data_str == "":return False# 组装 需依赖 的测试数据data_list = data_str.split(",")temp_dict["rely_case_id"] = data_list[0]temp_dict["all_data"] = {}for item in range(1, len(data_list)):if "headers" == data_list[item]:case_headers = opt_test_data.read_headers(now_case_id)if case_headers:temp_dict["all_data"]["headers"] = eval(case_headers)elif "data" == data_list[item]:case_data = opt_test_data.read_data(now_case_id)if case_data:temp_dict["all_data"]["data"] = eval(case_data)elif "response" == data_list[item]:case_response = opt_test_data.read_response(now_case_id)if case_response:temp_dict["all_data"]["response"] = eval(case_response)elif "file" == data_list[item]:case_filename = opt_test_data.read_files_name(now_case_id)temp_dict["all_data"]["file"] = case_filename# 把组装好的 需依赖数据 写入 需依赖用例的 依赖用例数据 中opt_test_data.write_rely_on_case_data(int(temp_dict["rely_case_id"]), str(temp_dict["all_data"]))return temp_dictdef dict_str(test_data_str):"""将从测试用例中读取出来的字符串转换成字典:param test_data_str: 读取出来的字符串:return: 字典"""if test_data_str:return eval(test_data_str)return Nonedef get_expression_data(pattern, data_dict):"""根据传入表达式pattern匹配数据data中的数据:param pattern: 表达式:param data_dict: 匹配数据:return: dict{'var1': 'headers', 'var2': 'response'}"""var_dict = {}pattern_list = pattern.split(",")# print(pattern_list)for item in pattern_list:temp_list = item.split("=")# 获取变量名称temp_var = temp_list[0]# 分析表达式var_dict[temp_var] = _dict_path_value(temp_list[1], data_dict)return var_dictdef replace_data(var_data, data_str):"""根据传入的 var_data, 修改 data 中的字符串:param var_data: 表达式从依赖用例数据中取出的变量字典:param data_str: 需要替换的对象字符串(从用例中取出的请求头等):return: 修改过的 请求数据 dict"""for item in var_data:data_str = data_str.replace(item, var_data[item])return data_strdef assert_data(case_id, assert_str):"""根据assert_str的断言,判断 实际结果 和 预期结果 之间的关系:param assert_str: 断言 "headers.key1 equal key1_123":param case_id: 测试用例id:return: pass fail"""result_str = ""actual = eval(opt_test_data.read_response(case_id))assert_list = assert_str.split(",")for item in assert_list:my_assert = re.findall(r"\s\S+\s", item)[0].strip()pattern_left = re.findall(r"\S+\s", item)[0].strip()pattern_right = re.findall(r"\s\S+", item)[1].strip()if "equal" == my_assert:data_left = _dict_path_value(pattern_left, actual)data_right = pattern_rightif data_left == data_right:result_str += "检查点>实际结果:%s等于预期结果:%s pass \n" % (data_left, data_right)else:result_str += "检查点>实际结果:%s不等于预期结果:%s fail \n" % (data_left, data_right)elif "notequal" == my_assert:data_left = _dict_path_value(pattern_left, actual)data_right = pattern_rightif data_left != data_right:result_str += "检查点>实际结果:%s等于预期结果:%s pass \n" % (data_left, data_right)else:result_str += "检查点>实际结果:%s不等于预期结果:%s fail \n" % (data_left, data_right)elif "in" == my_assert:data_left = _dict_path_value(pattern_left, actual)data_right = pattern_rightif data_left in data_right:result_str += "检查点>实际结果:%s等于预期结果:%s pass \n" % (data_left, data_right)else:result_str += "检查点>实际结果:%s不等于预期结果:%s fail \n" % (data_left, data_right)elif "notin" == my_assert:data_left = _dict_path_value(pattern_left, actual)data_right = pattern_rightif data_left not in data_right:result_str += "检查点>实际结果:%s等于预期结果:%s pass \n" % (data_left, data_right)else:result_str += "检查点>实际结果:%s不等于预期结果:%s fail \n" % (data_left, data_right)return result_strdef _dict_path_value(path, data):"""根据path获取dict_data里面的值"""num = 1pahts = path.split(".")mydict = {}for p in pahts:if num == 1:mydict = data[p + ""]num = num + 1else:mydict = mydict[p + ""]num = num + 1return mydict
# opt_test_data.py
def read_is_run(case_id):"""读取该条用例的 是否执行 信息"""is_run = remove_str_all_break(get_case_row_data(case_id)[6])if len(is_run) <= 0:return Nonereturn is_rundef write_is_run(case_id, content):"""修改该条用例的 是否执行 信息"""case_row_number = get_case_row_number(case_id)test_case_data().replace_data(case_row_number, 6, content)def read_rely_on_case(case_id):"""读取该条用例的 被依赖用例/依赖内容 信息"""rely_on_case = remove_str_all_break(get_case_row_data(case_id)[7])if len(rely_on_case) <= 0:return Nonereturn rely_on_casedef write_rely_on_case(case_id, content):"""修改该条用例的 依赖用例 信息"""case_row_number = get_case_row_number(case_id)test_case_data().replace_data(case_row_number, 7, content)def read_rely_on_case_data(case_id):"""读取该条用例的 需依赖用例数据 信息"""case_data = remove_str_all_break(get_case_row_data(case_id)[8])if len(case_data) <= 0:return Nonereturn case_datadef write_rely_on_case_data(case_id, content):"""修改该条用例的 需依赖用例数据 信息"""case_row_number = get_case_row_number(case_id)test_case_data().replace_data(case_row_number, 8, content)def read_rely_on_case_expression(case_id):"""读取该条用例的 需依赖用例取值表达式 信息"""case_expression = remove_str_all_break(get_case_row_data(case_id)[9])if len(case_expression) <= 0:return Nonereturn case_expressiondef write_rely_on_case_expression(case_id, content):"""修改该条用例的 需依赖用例取值表达式 信息"""case_row_number = get_case_row_number(case_id)test_case_data().replace_data(case_row_number, 9, content)def read_rely_on_case_expression_result(case_id):"""读取该条用例的 需依赖用例取值表达式取值结果 信息"""expression_result = remove_str_all_break(get_case_row_data(case_id)[10])if len(expression_result) <= 0:return Nonereturn expression_resultdef write_rely_on_case_expression_result(case_id, content):"""修改该条用例的 需依赖用例取值表达式取值结果 信息"""case_row_number = get_case_row_number(case_id)test_case_data().replace_data(case_row_number, 10, content)def read_api_path(case_id):"""读取该条用例的 api地址 信息"""api_path = remove_str_all_break(get_case_row_data(case_id)[11])if len(api_path) <= 0:return Nonereturn api_pathdef write_api_path(case_id, content):"""修改该条用例的 api地址 信息"""case_row_number = get_case_row_number(case_id)test_case_data().replace_data(case_row_number, 11, content)def read_headers(case_id):"""读取该条用例的 请求头 信息"""headers = remove_str_all_break(get_case_row_data(case_id)[12])if len(headers) <= 0:return Nonereturn headersdef write_headers(case_id, content):"""修改该条用例的 请求头 信息"""case_row_number = get_case_row_number(case_id)test_case_data().replace_data(case_row_number, 12, content)def read_method(case_id):"""读取该条用例的 请求方法 信息"""method = remove_str_all_break(get_case_row_data(case_id)[13])if len(method) <= 0:return Nonereturn methoddef write_method(case_id, content):"""修改该条用例的 请求方法 信息"""case_row_number = get_case_row_number(case_id)test_case_data().replace_data(case_row_number, 13, content)
# request_client.pydef main(self):# 获取所有需要执行的用例id列表all_test_count_list = opt_test_data.get_test_run_order()for item in all_test_count_list:# 判断本条用例是否需要被执行is_run = opt_test_data.read_is_run(item)try:if is_run == "Y" or is_run == "y":# 写入开始执行时间opt_test_data.write_start_time(item, my_time.now_time())# 判断本条用例是否需要依赖数据# 获取 需依赖用例的数据 和 需依赖用例的表达式rely_on_case_data = opt_test_data.read_rely_on_case_data(item)rely_on_case_expression = opt_test_data.read_rely_on_case_expression(item)if rely_on_case_data and rely_on_case_expression:# 准备本条需要依赖的数据self.write_rely_data(item, rely_on_case_expression, rely_on_case_data)# 如果 接口地址\请求头\请求方法\请求数据\文件名称 中需要依赖数据,则使用依赖数据替换self.replace_request_data(item)# 接下来流程一样self._send_end(item)# 不需要依赖数据else:# 接下来流程一样self._send_end(item)# 打印一下本条用例基本情况self.print_now_status(item)else:# 本条用例不执行,执行下一条continueexcept Exception as e:self.print_now_status(item)print(e)print(traceback.print_exc())opt_test_data.write_status(item, str(traceback.format_exc()))finally:# 写入本条用例执行完成时间self._end_time(item)# 写入本条用例的执行人self._write_executor(item)# 计算本条用例总共花费时间并写入消耗时间中self._write_total_time(item)

基于excel实现接口自动化测试相关推荐

  1. 基于jmeter的接口自动化测试平台

    基于jmeter的接口自动化测试平台安装说明及文件包:  下载地址 一.背景 1.隶属于研发中心部门,主要研发微服务中台产品.项目产品: 2.相关产品系统对外提供批量的接口api,需要人工进行接口测试 ...

  2. 基于pytest搭建接口自动化测试框架,提供源码

    基于pytest搭建接口自动化测试框架 框架整体介绍和方法教程 新框架(比这个功能多了很多,用例使用yaml编写) 源码框架结构 xmind项目结构介绍 源码地址 使用教程 1.全局变量设置和使用 2 ...

  3. python自动化测试脚本后端_基于 python 的接口自动化测试

    本文来自作者:孙彦辉 在 GitChat 上精彩分享,「阅读原文」看看大家和作者交流了哪些问题 一.简介 本文从一个简单的登录接口测试入手,一步步调整优化接口调用姿势: 然后简单讨论了一下接口测试框架 ...

  4. 基于 python 的接口自动化测试,让你轻松掌握接口自动化

    目录 目录 一.简介 ​编辑二.引言 三.环境准备 四.测试接口准备 接口信息 五.编写接口测试 六.优化 封装接口调用 一.简介 本文从一个简单的登录接口测试入手,一步步调整优化接口调用姿势: 然后 ...

  5. 软件测试须知基于PostMan的接口自动化测试

    临近年底,公司任务也不是很多,趁这个机会老大让我研究了一下PostMan的脚本自动化测试.作为一个前端开发,说实话,对于PostMan的操作,仅仅限于新建请求->填写url地址和参数->s ...

  6. 基于python的界面自动化测试-基于python的接口自动化测试+ddt数据驱动

    在测试接口时,一个接口会先写好测试用例,这个用例主要针对功能,传入参时考虑到各种场景,正常的,异常的,如:参数缺省,参数传一个六位数字写用例时考虑边界情况等. 一个接口设计用例时有可能会十几条到几十条 ...

  7. 基于Python的接口自动化测试框架

    项目背景 公司内部的软件采用B/S架构,目的是进行实验室的数据存储.分析.管理. 大部分是数据的增删改查,但是由于还在开发阶段,所以UI的变化非常快,难以针对UI进行自动化测试,那样会消耗大量的精力与 ...

  8. python+unittest+excel接口自动化_Python+requests+unittest+excel实现接口自动化测试框架

    一.框架结构: 工程目录 二.Case文件设计 三.基础包 base 3.1 封装get/post请求(runmethon.py) 1 import requests 2 import json 3 ...

  9. 基于python的界面自动化测试-基于 Python 的接口自动化测试实例

    1 转换测试数据 1.1将用例数据(红色部分)从excel读取出来,并保存在列表中 测试用例写在excel里面,第一列是编号,第二列到倒数第六列是填写的测试数据, 最后五列分别是用例描述,提交数据,结 ...

最新文章

  1. 一对一直播app源码功能操详解方案分享
  2. UOJ【UR #12】实验室外的攻防战
  3. MFC Combo-box显示大小
  4. .GRIDVIEW奇偶行变色
  5. hdu 2586(LCA的离线做法)
  6. 【XLL 框架库函数】 TempActiveCell/TempActiveCell12
  7. MySQL查询结果导出到文件
  8. 关于COCOS2D-X 中的音乐与音效应用的备注
  9. python爬虫----handler和opener
  10. DIP、IoC、DI笔记整理
  11. 国资入局,苏宁“零售服务商”升级战略获得最强助力
  12. SecureCRT通过vim打开文件时显示行号
  13. CentOS系统下各文件夹的作用
  14. 1526 B. I Hate 1111
  15. JavaFX入门(一):我的第一个JavaFX程序
  16. 新版kettle学习
  17. Ubuntu22.04更换国内镜像源(阿里、网易163、清华、中科大)
  18. Gradle下载超时
  19. 租户隔离怎么做MYSQL_一种SaaS软件租户数据隔离的方法与流程
  20. 13-寄存器编写程序入门

热门文章

  1. 步进电机S曲线加减速控制生成器-VB6.0实现
  2. 计算机考研二外,广东外语外贸大学英语考研二外,广外考研二外英语难度如何?...
  3. java开发srm系统_SRM系统需要实现的核心功能有哪些?
  4. C#中的构成:Program.cs、Form1.cs、Form1.Designer.cs
  5. 凡普金科:“凡普公益基金会”正式运行 全力践行社会责任
  6. 第二部分 单机以及编队控制实验—初级教程(4)
  7. 基于可编程超表面的雷达通信一体化系统
  8. SEC'' 2018: ACM/IEEE Symposium on Edge Computing 总结(二)
  9. 腾讯短信集成报错误:NoClassDefFoundError: org/apache/http/client/config/RequestConfig
  10. 一个项目整个生命周期