关于前端接口测试的探索和挖坑

开始

最近几年,前端测试渐渐被人重视,相关的框架和方法已经比较成熟。
断言库有should, expect, chai。 单元测试框架有mocha, jasmine, Qunit。 模拟浏览器测试环境有Phantomjs, Slimerjs。 集成测试任务管理工具备karma。此外,还有一堆诸如Selenium、nightwatch(冰火出戏)等各色思路不一样的关注UI测试的工具。
本文主要关注的是接口测试。
接口是先后端协做的桥梁,是系统得以顺利运行的关键。所谓接口测试,就是检查系统提供的接口是否符合事先撰写的接口文档。数据结构是否完备,数据类型和取值是否符合标准。
实际上,接口测试由后端来作会比较方便,可是因为一些实际缘由(后端大哥比较忙,人手不足等),后端每每不能确保接口数据必定符合接口文档规定。此时,做为前端,咱们为何不能另辟蹊径,探索一番呢?css

思路分析

接口测试最大的难点是什么?我以为是登陆状态的获取
众所周知,一个系统的大部分接口都只会对登陆用户开放。在测试接口以前,首先必须确保此次会话已经登陆,发送给后台的请求中必须携带登陆后获取的 cookie。面对这个问题,最直接的想法是在后台模拟登陆。html

后台模拟登陆

mocha 能够运行在node中,理论上咱们彻底能够在node环境下,使用一些http client( request, superagent等),模拟进行登陆。手动获取cookie,并加在以后的每一次接口请求中。得到到接口数据后,就能够结合 mocha,愉快地进行测试了。
但是,实际实验以后,我发现这个方案存在一些缺陷。前端

  1. 难以封装复用
    不一样系统的登陆流程并不相同。至关多的系统要求在登陆时须要附带其余的 cookie 或者额外的表单参数。
    以本人测试的系统为例,登陆时就须要带上一个 key 为 jsessionid 的 cookie,以及一个 key 为 nlt 的表单参数。这个 cookie 是怎么来的呢?是访问登陆页时返回的 set-cookie 头设置的。这个表单参数又是怎么来的呢?是藏在登陆页面的表单中的一个隐藏域。
    因此,若是简单地用 http client 向登陆地址发一个 post 请求,仅仅带上本身的用户名密码,你就会发现,登陆毫无疑问的···失败了。
    更烦人的是,若是你的系统登陆依赖 SSO,内部存在 302 请求转发,那么颇有可能会出现 cookie 丢失的状况(有两个 set-cookie header,浏览器能识别并正确设置,可是不少 http client 只能拿到最后一个)。
    咱们固然能够动用各类奇技淫巧,手动获取和设置各类特定的 cookie,去网页里爬出隐藏域的值。但是,这一切,仅仅对特定的系统有效。若是换一套系统,你就必须从新研究一遍登陆流程,从新写一遍模拟登录代码,感受仍是挺崩溃的。node

  2. 难以应对验证码
    上面的问题仅仅只是使用不便,这个问题就是直接就给该方案判了死刑。固然,爬虫界也有很多应对验证码的解决方案,好比依托 OCR 软件啊,人工判别 API 啦, 更厉害的还有本身作图像处理和算法进行识别。但是,做为一个简单的接口测试,这种方案是否是过小题大作了点?webpack

浏览器扩展

mocha 也能够在浏览器环境运行,当后台模拟登录遇到困难,咱们很容易想到,在浏览器环境进行测试是否可行呢?
普通的浏览器环境确实会有必定问题,那就是前端的老大难:跨域
咱们的目的是前端接口测试,原则上不该也不能让后台搭配测试工做去改接口,因此,CORS,jsonp 都是不可行的。
难道这条路又堵死了?非也,咱们还有一个选项,那就是——浏览器扩展。
以 chrome extension 为例,只要在 manifest.json 文件中配置好 permissions ,扩展发起的请求就能够成功跨域。事实证实,彻底没有问题。不只能够跨域,还能够携带登陆后的 cookie,因此,只要在浏览器正常登陆后,再打开插件相关页面进行验证,就能够解决登陆状态的问题。简直完美。web

方案设计

既然定下了方案,下一步就是设计。做为接口测试的解(wa)决(keng)方(zhi)案(lv),咱们必须具有通用性与易用性。使用者只需提供配置,不须要再进入源代码修改打包。
本方案中中测试框架和断言使用 mocha + chai。这方面的资料汗牛充栋,本篇再也不赘言。算法

目录结构

apiTest
    │  package.json
    │  webpack.conf.js
    │  api.conf.dist.js
    │  api.conf.dist.js.map
    │  index.js
    │  manifest.json
    │  test.png
    ├─config
    │  index.js
    ├─css
    ├─html
    ├─js
    ├─lib
    └─TestCreator

其中,index.js 是入口文件; manifest.json 是 chrome 插件配置文件; config/index.js 是用户测试配置文件。css, html, js, lib 都用于存放资源文件。chrome

使用流程

  1. 安装插件(若是已安装过就能够省略)npm

  2. 提供测试配置json

  3. 用户去系统登陆页完成登陆

  4. 点击插件图标,打开新 tab 页

  5. 在 tab 页中进行测试,并在页面上显示结果

让咱们从 manifest.json 文件开始,一步一步深刻,看目标流程是如何实现的。

- manifest.json

"permissions": [
    "tabs",
    "http://*/*",
    "https://*/*"
],
"background": {
   "scripts": "js/background.js"
}

在 manifest.json 文件中,定义 background 属性。定义的 js/background.js 文件将自动在后台运行。permissions 属性定义了扩展的权限。“tabs”指明能够打开浏览器自己的 tab 标签页,后面两个配置指明浏览器能够向任何 url 发送请求。(不配置会跨域)


- js/background.js

chrome.browserAction.onClicked.addListener(function(){
  var url = chrome.extension.getURL("../html/main.html");
  window.open(url, "main_page");
})

在 js/background.js 文件中,注册了一个事件函数。当用户点击插件图标时,打开一个 html/main.html 做为新的 tab 页。咱们全部的任务都将在这个 tab 页中实现。


- html/main.html

<!doctype html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <link rel="stylesheet" type="text/css" href="../css/demo.css">
  <link rel="stylesheet" type="text/css" href="../css/mocha.css">
  <script src="../lib/mocha.js"></script>
  <script src="../config/index.js"></script>
  <script src="../api.conf.dist.js"></script>
</head>
<body>
  <div id="ext-box">
    <button id="startBtn">请在登录后点击按钮开始测试</butotn>
  </div>
  <div id="mocha"></div>
</body>
</html>

在这个 html 中,载入了三个 js 文件。其中,config/index.js 是测试配置文件。api.conf.dist.js 是入口文件经 webpack 打包后的压缩文件。mocha 之因此独立载入,是由于在浏览器环境中,mocha 必须部署在 window 对象下,因此不能打包进去。核心的逻辑代码,放在 api.conf.dist.js 文件中。
页面中放置了一个按钮和一个 id 为 mocha 的 div。前者点击后会触发 mocha 执行,后者做为一个容器,用于显示测试结果。


- index.js

import {expect} from 'chai'
import test from './js/main'

function click(e) {
  mocha.run()
  document.querySelector("#startBtn").style.display = 'none';
}

document.addEventListener('DOMContentLoaded', function () {
  var btn = document.querySelector("#startBtn")
  btn.addEventListener('click', click);
});

mocha && mocha.setup('bdd')
mocha.timeout(4000)

const mainTest = testCreator(window.apiTestConf)
mainTest()

index.js 是打包的入口文件。这里主要作了两件事:
第一,为按钮定义了一个事件监听函数,点击时执行 mocha。
第二,初始化 mocha,设置其执行模式(bdd)和超时时间。
第三,执行 mainTest 函数,在这里定义了全部测试用例。测试用例根据用户配置文件动态,这也是核心逻辑。下面将进一步详述。


测试配置的设计

下面展现本文使用的测试配置:

window.apiTestConf = {
  name:"foo",
  path:"http://baz/japi/platform/",
  common:{
    success: {
      value: true,
      type:["boolean"],
    },
    errorCode: {
      value: [0]
    }
  },
  publicStruc:[
    "results>items",
    "results"
  ],
  apis:{
    AccountCenter:{
      "110620001":{
        name:"获收货地址列表",
        fullUrl:false,
        data:{
          length:{
            min:1
          },
          item:{
            area:{
                type:"string"
            },
            areaStr:"string",
            consignee:"string",
            detail:"string",
            id:"number",
            ifDefault:"boolean",
            mobile:["string","number"]
          }
        }
      }
    }
  }
}

测试配置决定了测试用例的组织和测试用例内断言的编写。其结构学习了一些表单验证插件,比表单验证插件复杂的地方在于,表单验证仅仅针对一维的单一字段,而接口返回的数据则是具有必定的嵌套结构的。下面对该配置进行简述。

  • path:接口地址的公共部分。

  • common:对接口返回数据的格式上的公共部分进行验证。好比 success 必须为 true,errorcode 必须为 0 等。

  • publicStruc:接口核心数据部分的路径。系统将根据该路径一步步寻找。若是没找到将会在断言中报错。若是定义了多个路径,则会按顺序从前日后查找。

  • apis:核心部分,对接口数据进行验证。

  • AccountCenter:该 key 可变。在这一层级对接口进行分组,好比 AccountCenter 说明下面定义的是帐户中心的接口的测试配置。

  • 110620001:该 key 可变。这是真实接口的路径。该 key 值下的对象,就是针对具体数据结构和字段进行配置了。下面将介绍这部分的配置和验证规则,可能会有点枯燥,不感兴趣的读者能够略过不看。

字段验证规则

字段验证规则:
字段验证规则指的是接口下data属性下定义的规则。是对接口核心数据的存在与否、数据类型和值所作的规定

  1. 基本规则规则

    • 规则仅仅对类型是数字,字符串,布尔值和数组的字段有效,若是要验证的字段是对象,则不起做用。须要对对象内的属性(一样看作字段)作进一步的验证,而不是对对象自己作验证。

    • 验证属性可写的值是对象,数组和字符串,其余类型的值都是非法的

    • 验证属性若是是一个空对象,则直接经过。

    • 验证属性若是是一个数组或字符串,则视为 type 处理

    • 验证属性若是是一个至少包含了required, value, type三者之一的对象,则进行标准化验证

  2. required

    • 验证真实字段必须指定,且必须不为空字符串(也就是说false,0能经过验证。)

  3. value

    • 若是 value 是数组,则验证真实值是否至少等于数组中的某一个值

    • 若是 value 是数字,字符串或者布尔值,验证真实值与其是否相等

    • 若是 value 是一个对象,则进一步判断:

      • min:规定最小值,仅仅对数字有效

      • max:规定最大值,仅仅对数字有效

      • not:不为其值。能够是一个数组,此时不为数组中的全部值

      • start:开始字符,仅仅对字符串有效

      • end:结束字符串,仅仅对字符串有效

  4. type

    • type 可写的值是字符串。这些字符串的可选值为:"number","string","boolean","array"。没有"object","undefined","null",由于没有意义

    • type 能够是一个数组,数组中的值也是上面的可选值。此时,只要知足数组中的一个值,就能经过验证

  5. length
    当数据是数组时才有效,是对数组长度作的验证

    • min:规定最小值,仅仅对数字有效

    • max:规定最大值,仅仅对数字有效

  6. item

    当数据是数组时才有效,里面进一步规定对数组中每一项的验证

设计完各类规则后,接下来就是依样画葫芦地编写代码了。因为代码量比较多,这里就再也不赘述。其核心思想就是根据配置项生成各类测试用例和断言。最后供 mocha 运行,输出结果。

clipboard.png

结束和展望

本文所设计的方案基本可以知足前端接口测试的要求,但仍是有一些缺陷,弊端,及有待改进的地方。

  1. 验证规则涉及不够全面和严密,有待丰富,

  2. 能够将整体目录结构以及内部的 TestCreater 封装成 npm 包,更方便使用。

  3. 测试经过时,没法看到经过了哪些断言。测试失败时,只输出未经过的第一条断言的信息。输出信息不够全面丰富。这必定程度上是 mocha 和 chai自己的特性,不知道有什么方式能够优化。

最后,本文中若出现了错误,或是读者有更好的方案,望不吝啬赐教。

相关文章
相关标签/搜索