遇到的困扰

接口测试对于大多数的公司来说,基本是一个常规武器,我们也在 Testerhome 的社区中学习到了很多同学分享出来的接口测试框架。不过除了平时使用 Jenkins 做接口的持续回归之外,我们的产品测试同学也会经常需要对一些接口进行一些手工的操作,CRUD 等等。目前业内有一些比较主流的接口测试工具,例如:

  1. Chrome + Postman
  2. Firefox + Rest Client
  3. Mac 下的Paw (商业)
  4. JMeter

上述的工具都可以完成基本的 HTTP 请求,并且支持标准的 HTTP Authentication 以及对于 HTTP Header 的操作。但是我们的接口有一些特殊,需要对于每一个 URL 进行一个签名的操作。如果 signature 是一个函数的话,那么输入的参数就是时间戳 +URL ,输出就一个 signature 字符串,并且需要添加到 HTTP 头中作为一个校验字段。这样就意味着每一次请求都需要去计算一次 signature。


我们想过的一些方案

写一个 Python 脚本来专门计算 Signature,然后产品同学把脚本输出的结果填写到 Postman 中的 HTTP Header 头中来发请求 。想想这个效率实在是太低了,直接放弃。

JMeter 是一个压力测试工具,不过我们也看到有一些团队用它来做一些接口测试的工作。BeanShell 是 JMeter 支持的一个脚本语言,可以用来在 HTTP 请求前后做一些操作,例如修改请求参数,和 HTTP Header 头等。我们可以考虑把我们计算 Signature 的方法写在一个 BeanShell PreProcessor 中,这样就每次发送请求的时候,自动计算签名了。但是考虑到很多同学都没有使用过 JMeter,还有培训和掌握新工具的过程,所以还是放弃了。(充分考虑了产品测试小红薯们的对新测试工具的接受程度)


最终的解决方案

观察了很久后我们发现,其实小伙伴们都喜欢用 Chrome + Postman 的 Extension 来做接口的调试工作。那看来最好的方法,就是给他们发布一个新的 Chrome Extenstion 就能解决问题。当然我们不需要重头开始写,我们要做的就是在巨人的肩膀上加一个计算签名的功能。不过令人伤心的是 Postman 不是一个开源的项目,好在我们最后在 Github 上找到了这个项目ChromeRestClient, Chrome 上另外一个很流行的 Rest Client 插件。

如何做 Chrome Extension 开发我们就不在这里详述了,有兴趣的小伙伴可以移动到这里 Chrome Extension Development

ChromeRestClient 项目比较庞大,项目结构如下,

但是其中实际和 Chrome Extension 插件相关的目录是

搭建开发环境的过程很简单,只需要本地有安装 nodejs 即可, 我们使用的版本是 6.3.1, 接下来只要把项目从 github 克隆下来以后,在根目录下运行 npm install && bower install,就会在 app 目录下下载对应的依赖了。当然整个过程自然不会那么的一帆风顺,我们给社区反馈了 3 个 issue 并得到了开发者的及时反馈。

安装完依赖以后,使用 Chrome 浏览器,打开 Menu->More Tools -> Extensions, 选择Load Unpacked Extension, 然后选择 app 目录即可把本地的 extension 加载到 Chrome 中进行调试, 确保 app 目录下有manifest.json文件,这是一个 Chrome Extension 的描述文件

接下来就可以在 Chrome 中进行插件调试开发了,如果本地修改了代码,需要在 Extension 菜单页面中,选择 Reload,重新加载你的插件。由于 Chrome Extension 使用的是标准的 Web 开发技术,包括 HTML + CSS + Javascript,所以可以方便的在 Chrome Develop Toolbar 中进行 Debug 了。

ChromeRestClient 插件的页面是使用了 Google 的 Polymer 项目进行开发,这个和 AngularJS 类似,都属于 Google 在力推的 Web Component 技术。我们可以在app/elements/下找到一堆子目录,都是 Polymer 的 Plugin。当然我们最关心的是这个子目录arc-request-controller

我们可以看到arc-request-controller.js中,最核心的一个函数是sendRequest,

sendRequest: function () {
      if (!this.request) {
        StatusNotification.notify({
          message: 'Request not ready'
        });
        return;
      }
      if (!this.request.url) {
        StatusNotification.notify({
          message: 'Add URL to the request first'
        });
        return;
      }

      this._setIsError(false);
      this._setResponse(null);
      this._setRequestLoading(true);
      this._saveUrl();
      this._callRequest();
      this.showCookieBanner = false;
      arc.app.analytics.sendEvent('Engagement', 'Click', 'Request start');
      // Will help arrange methods bar according to importance of elements.
      arc.app.analytics.sendEvent('Request', 'Method', this.request.method);
    },

上面的代码中,大多数都是在做一些 Request Body 的初始化操作,最核心的是那句this._callRequest()调用,我们来看一下_callRequest的函数式怎么实现的


_callRequest: function () {
      // Copy the object so MagicVariables will not alter the view
      this._applyMagicVariables(Object.assign({}, this.request))
        .then((request) => this._applyCookies(request))
        .then((request) => this._applyAuthorization(request))
        .then((request) => this.fu(request))
        .then((request) => {
          // Make it async so errors will be handled by socket object.
          this.async(() => {
            if (this.auth) {
              request.auth = this.auth;
              this.auth = undefined;
            }
            if (this.useXhr) {
              this.$.xhr.request = request;
              this.$.xhr.run();
            } else {
              this.$.socket.request = request;
              this.$.socket.run();
            }
          });
        });
    },

接下来我们可以看到负责处理 HTTP Header 头的是_filterHeaders函数,那么我们只要把我们的签名算法写到这个函数里,并添加正确的 HTTP Header 就好了。在添加签名算法的过程中涉及到了一下 JS 的依赖,我们也统一用 bower 进行管理,并把依赖模块加入到了bower.json

最后我们使用 Gulp 来编译我们的 Chrome Extension,例如编译一个 beta 的版本 gulp build --target beta --build-only, 这样就会在 build 目录下创建一个 beta 目录,并把对应的 build 结果 copy 到里面。

有一个要提醒,如果有添加 JS 依赖的话,需要在tasks/builder.js中声明这个依赖

var bowerDeps = [
    'chrome-platform-analytics/google-analytics-bundle.js',
    'dexie-js/dist/dexie.min.js',
    'har/build/har.js',
    'lodash/lodash.js',
    'uri.js/src/URI.js',
    'prism/prism.js',
    'prism/plugins/autolinker/prism-autolinker.min.js',
    'js-md5/src/md5.js',
    'string-format-js/format.js'
  ];

万事大吉,接下来只要使用 Chrome 自带的 Pack Extension 功能把插件打包成一个.crx 的文件就可以分发给我们的产品测试同学了。(签名算法涉及到一些机密信息,所以我们没有上传到 Chrome Store 中)

希望这篇分享可以让你更好了解小红薯是如何在测试的工作中 think different 的,当然我们也更欢迎你加入我们的团队,和我们一起把测试变得有趣。有兴趣的同学可以看这篇招聘帖子,https://testerhome.com/topics/5045


↙↙↙阅读原文可查看相关链接,并与作者交流