基于Python的接口测试框架实例


Posted in Python onNovember 04, 2016

背景

最近公司在做消息推送,那么自然就会产生很多接口,测试的过程中需要调用接口,我就突然觉得是不是可以自己写一个测试框架?

说干就干,由于现有的接口测试工具Jmeter、SoupUI等学习周期有点长,干脆自己写一个吧,不求人,所有功能自己都能一清二楚。

当然,写工具造轮子只是学习的一种方式,现成成熟的工具肯定比我们自己的写的好用。

开发环境

-------------------------------------------------------------

操作系统:Mac OS X EI Caption

Python版本:2.7

IDE:Pycharm

-------------------------------------------------------------

分析

接口是基于HTTP协议的,那么说白了,就是发起HTTP请求就行了,对于Python来说简直就是小菜一碟。直接使用requests就可以很轻松的完成任务。

架构

整个框架是比较小的,涉及的东西也比较少,只要分清楚几个模块的功能就行了。

基于Python的接口测试框架实例

上面是一个接口测试的完整流程。只要一步一步的走下来就行了,并不是很难。

数据源

数据源我使用的是JSON来保存,当然,比较广泛的是使用Excel来保存,用JSON来保存是因为JSON用起来比较方便,懒得去读取Excel了,Python对JSON的支持是非常友好的。当然这个就看个人喜好了。

{
  "TestId": "testcase004",
  "Method": "post",
  "Title": "单独推送消息",
  "Desc": "单独推送消息",
  "Url": "http://xxx.xxx.xxx.xx",
  "InputArg": {
   "action": "44803",
   "account": "1865998xxxx",
   "uniqueid": "00D7C889-06A0-426E-BAB1-5741A1192038",
   "title": "测试测试",
   "summary": "豆豆豆",
   "message": "12345",
   "msgtype": "25",
   "menuid": "203"
  },
  "Result": {
   "errorno": "0"
  }
 }

示例如上面代码所示,可以根据个人的业务需要进行调整。

发送请求

发送请求就很简单了,用requests模块,然后从JSON中读取发送的参数,post、get或者其他。由于要生成测试报告,那么发送的数据需要做一下记录,我选择用txt文本来作为记录的容器。

f = file("case.json")
testData = json.load(f)
f.close()


def sendData(testData, num):
  payload = {}
  # 从json中获取发送参数
  for x in testData[num]['InputArg'].items():
    payload[x[0]] = x[1]
  with open('leftside.txt', 'a+') as f:
    f.write(testData[num]['TestId'])
    f.write('-')
    f.write(testData[num]['Title'])
    f.write('\n')

  # 发送请求
  data = requests.get(testData[num]['Url'], params=payload)
  r = data.json()

接受返回

由于我们是需要生成测试报告的,那么返回的数据我们先需要进行一次存储,可以选择用数据库存储,但是我觉得数据库存储太麻烦了,只要用txt文本作为存储容器即可。

with open('rightside.txt', 'a+') as rs:
    rs.write('发送数据')
    rs.write('|')
    rs.write('标题:'+testData[num]['Title'])
    rs.write('|')
    rs.write('发送方式:'+testData[num]['Method'])
    rs.write('|')
    rs.write('案例描述:'+testData[num]['Desc'])
    rs.write('|')
    rs.write('发送地址:'+testData[num]['Url'])
    rs.write('|')
    rs.write('发送参数:'+str(payload).decode("unicode-escape").encode("utf-8").replace("u\'","\'"))
    rs.write('|')
    rs.write(testData[num]['TestId'])
    rs.write('\n')

结果判定

结果判定我使用的是全等于判定。因为我们的接口只需要这样处理就行了,如果有需要,可以写成正则判定。

with open('result.txt', 'a+') as rst:
    rst.write('返回数据')
    rst.write('|')
    for x, y in r.items():
      rst.write(' : '.join([x, y]))
      rst.write('|')
    # 写测试结果
    try:
      if cmp(r, testData[num]['Result']) == 0:
        rst.write('pass')
      else:
        rst.write('fail')
    except Exception:
      rst.write('no except result')
    rst.write('\n')

我这里结果有3种,成功、失败或者没结果。结果的设置就看自己的定义了。

生成测试报告

测试报告是一个重头戏,由于我发送数据、返回数据和结果都是用txt文本存储,那么每次使用a+模式新增,会让结果越来越多,而且检查起来非常蛋疼。

我的处理方式是每次测试完毕之后,用Python读取txt文本中的数据,然后使用Django动态生成一个结果,然后再使用requests抓取这个网页,保存在Report文件夹中。

网页报告

Django的方法我就不多说了,博客中已经有一整个系列文章了。我们需要在views文件中打开之前记录的3个txt文件,然后做一些数据处理,返回给前端,前端用Bootstrap来渲染,就能生成一个比较漂亮的测试报告。

def index(request):
  rightside = []
  result = []
  rst_data = []
  leftside = []
  passed = 0
  fail = 0
  noresult = 0
  with open(os.getcwd() + '/PortTest/leftside.txt') as ls:
    for x in ls.readlines():
      lf_data = {
        'code': x.strip().split('-')[0],
        'title': x.strip().split('-')[1]
      }
      leftside.append(lf_data)

  with open(os.getcwd() + '/PortTest/rightside.txt') as rs:
    for x in rs.readlines():
      row = x.strip().split('|')
      rs_data = {
        "fssj": row[0],
        "csbt": row[1],
        "fsfs": row[2],
        "alms": row[3],
        "fsdz": row[4],
        "fscs": row[5],
        'testid': row[6]
      }
      rightside.append(rs_data)

  with open(os.getcwd() + '/PortTest/result.txt') as rst:
    for x in rst.readlines():
      row = x.strip().split('|')
      if row[len(row)-1] == 'fail':
        fail += 1
      elif row[len(row)-1] == 'pass':
        passed += 1
      elif row[len(row)-1] == 'no except result':
        noresult += 1

      rs_data = []
      for y in row:
        rs_data.append(y)
      result.append(rs_data)
  for a, b in zip(rightside, result):
    data = {
      "sendData": a,
      "dealData": b,
      "result": b[len(b)-1]
    }
    rst_data.append(data)
  return render(request, 'PortTest/index.html', {"leftside": leftside,
                          "rst_data": rst_data,
                          "pass": passed,
                          "fail": fail,
                          "noresult": noresult})

基本上都是一些很基础的知识,字符串分割等等。这里的数据处理为了方便,在获取数据存储的时候就要按照一定的格式来存储,views的方法就很容易做处理。

前端代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <link href="http://3water.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
  <script src="http://3water.com/jquery/2.0.0/jquery.min.js"></script>
  <script src="http://3water.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
  <div class="row">
    <div class="page-header">
      <h1>接口测试报告
        <small>Design By Sven</small>
      </h1>
    </div>
  </div>
  <div class="row">
    <div class="col-md-4">
      <h3>测试通过 <span class="label label-success">{{ pass }}</span></h3>
    </div>
    <div class="col-md-4">
      <h3>测试失败 <span class="label label-danger">{{ fail }}</span></h3>
    </div>
    <div class="col-md-4">
      <h3>无结果 <span class="label label-warning">{{ noresult }}</span></h3>
    </div>
  </div>
  <p></p>
  <div class="row">
    <div class="col-md-3">
      <ul class="list-group">
        {% for ls in leftside %}
          <li class="list-group-item"><a href="#{{ ls.code }}">{{ ls.code }} - {{ ls.title }}</a></li>
        {% endfor %}
      </ul>
    </div>
    <div class="col-md-9">
      {{ x.result }}
      {% for x in rst_data %}
        <div class="panel-group" id="accordion">
        {% if x.result == 'pass' %}
          <div class="panel panel-success">
        {% elif x.result == 'fail' %}
          <div class="panel panel-danger">
        {% elif x.result == 'no except result' %}
          <div class="panel panel-warning">
        {% endif %}

      <div class="panel-heading">
        <h4 class="panel-title">
          <a data-toggle="collapse" href="#{{ x.sendData.testid }}">
            {{ x.sendData.testid }} - {{ x.sendData.csbt }}
          </a>
        </h4>
      </div>
      <div id="{{ x.sendData.testid }}" class="panel-collapse collapse">
        <div class="panel-body">
          <b>{{ x.sendData.fssj }}</b><br>
          {{ x.sendData.csbt }}<br>
          {{ x.sendData.fsfs }}<br>
          {{ x.sendData.alms }}<br>
          {{ x.sendData.fsdz }}<br>
          {{ x.sendData.fscs }}
          <hr>
          {% for v in x.dealData %}
            {{ v }}<br>
          {% endfor %}
        </div>
      </div>
      </div>
      </div>
        <p></p>
      {% endfor %}
      </div>
      </div>
    </div>
    <script>
      $(function () {
        $(window).scroll(function () {
          if ($(this).scrollTop() != 0) {
            $("#toTop").fadeIn();
          } else {
            $("#toTop").fadeOut();
          }
        });
        $("body").append("<div id=\"toTop\" style=\"border:1px solid #444;background:#333;color:#fff;text-align:center;padding:10px 13px 7px 13px;position:fixed;bottom:10px;right:10px;cursor:pointer;display:none;font-family:verdana;font-size:22px;\">^</div>");
        $("#toTop").click(function () {
          $("body,html").animate({scrollTop: 0}, 800);
        });
      });
    </script>
</body>
</html>

测试报告效果图

基于Python的接口测试框架实例

最后

用Python写一个工具很容易,主要还是要能更方便地满足实际工作中的使用需要为目的。如果要做完整的接口测试,还是尽量使用已经成熟的工具。

PS:简单的造轮子也是学习原理的一个绝佳的方法。

以上这篇基于Python的接口测试框架实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python构造函数及解构函数介绍
Feb 26 Python
Python中用altzone()方法处理时区的教程
May 22 Python
Python3遍历目录树实现方法
May 22 Python
Python命令行解析模块详解
Feb 01 Python
PyQt5每天必学之拖放事件
Aug 27 Python
基于Python 装饰器装饰类中的方法实例
Apr 21 Python
numpy使用fromstring创建矩阵的实例
Jun 15 Python
对python中的高效迭代器函数详解
Oct 18 Python
教你如何编写、保存与运行Python程序的方法
Jul 12 Python
基于Python+Appium实现京东双十一自动领金币功能
Oct 31 Python
Python调用钉钉自定义机器人的实现
Jan 03 Python
python连接打印机实现打印文档、图片、pdf文件等功能
Feb 07 Python
浅谈Python爬取网页的编码处理
Nov 04 #Python
Django接受前端数据的几种方法总结
Nov 04 #Python
Python多维/嵌套字典数据无限遍历的实现
Nov 04 #Python
浅谈Python数据类型判断及列表脚本操作
Nov 04 #Python
浅谈python字典多键值及重复键值的使用
Nov 04 #Python
用Python将动态GIF图片倒放播放的方法
Nov 02 #Python
各种Python库安装包下载地址与安装过程详细介绍(Windows版)
Nov 02 #Python
You might like
PHP.MVC的模板标签系统(三)
2006/09/05 PHP
php下尝试使用GraphicsMagick的缩略图功能
2011/01/01 PHP
php中将网址转换为超链接的函数
2011/09/02 PHP
php提取身份证号码中的生日日期以及验证是否为成年人的函数
2015/09/29 PHP
通过MSXML2自动获取QQ个人头像及在线情况(给初学者)
2007/01/22 Javascript
判断脚本加载是否完成的方法
2009/05/26 Javascript
JavaScript Konami Code 实现代码
2009/07/29 Javascript
JavaScript 核心参考教程 内置对象
2009/10/13 Javascript
javascript函数中的arguments参数
2010/08/01 Javascript
jquery 获取标签名(tagName)示例代码
2013/07/11 Javascript
js读写cookie实现一个底部广告浮层效果的两种方法
2013/12/29 Javascript
中文输入法不触发onkeyup事件的解决办法
2014/07/09 Javascript
jQuery Mobile弹出窗、弹出层知识汇总
2016/01/05 Javascript
jquery实现ajax提交表单信息的简单方法(推荐)
2016/08/24 Javascript
bootstrap学习使用(导航条、下拉菜单、轮播、栅格布局等)
2016/12/01 Javascript
Javascript 制作图形验证码实例详解
2016/12/22 Javascript
你真的了解BOM中的history对象吗
2017/02/13 Javascript
jquery仿京东商品放大浏览页面
2017/06/06 jQuery
基于vue实现网站前台的权限管理(前后端分离实践)
2018/01/13 Javascript
JS构造一个html文本内容成文件流形式发送到后台
2018/07/31 Javascript
vue服务端渲染缓存应用详解
2018/09/12 Javascript
Vue 实现一个命令式弹窗组件功能
2019/09/25 Javascript
在layui中对table中的数据进行判断(0、1)转换为提示信息的方法
2019/09/28 Javascript
javascript实现弹幕墙效果
2019/11/28 Javascript
Angular之jwt令牌身份验证的实现
2020/02/14 Javascript
如何基于viewport vm适配移动端页面
2020/11/13 Javascript
django manage.py扩展自定义命令方法
2018/05/27 Python
python如何实现异步调用函数执行
2019/07/08 Python
numpy np.newaxis 的实用分享
2019/11/30 Python
喜诗官方在线巧克力店:See’s Candies
2017/01/01 全球购物
家庭户外服装:Hawkshead
2017/11/02 全球购物
Oracle性能调优原则
2012/05/03 面试题
调解协议书
2014/04/16 职场文书
特教教师先进事迹
2014/05/21 职场文书
销售经理工作失职检讨书
2014/10/24 职场文书
导游词之徐州-云龙山
2019/09/29 职场文书