接口测试 让接口测试成为合格的桥梁——本地搭建 Swagger-UI 环境搭建

不二家 · 2017年03月31日 · 最后由 jwang 回复于 2019年10月30日 · 4405 次阅读
本帖已被设为精华帖!

前言

接口测试是自动化测试过程中,投入产出比相对而言比较大的工作,我们组之前一直在用 Jmeter 执行接口测试工作,然后通过 Jenkins 调度执行 Jmeter,给出测试报告。

测试报告如下:

痛点

  • 客户端开发不能在线调试某个接口
  • 客户端开发仍然需要跟服务端开发对接接口,我们组不能成为一个好的桥梁
  • 我们接口测试反馈的结果,服务端开发和客户端开发同学都很少关注

明确了存在的问题之后,又经过跟客户端同学开发的调研,发现他们希望我们在测试过接口之后,有这样一个页面,可以供他们使用。

需求:

  • 可以让他们在线调试接口
  • 可以让他们明确看到有关接口的定义
  • 可以让他们有正确可执行的 curl 命令
  • 可以看到有关这个接口的当前是否可执行的状态

显然这个时候我们展示的 HTML 静态页面,已经不能达到他们的需要了。

由于服务端开发接口开发完毕之后,提供了 Swagger UI 页面,但是他们可能由于某些原因,并没有设置header,导致客户端开发基本不能调试,只能作为对接口的参数设置的大致了解,并没有起到相应的效果。

我们的思路就是借鉴服务端开发使用的 Swagger UI,定制化我们自己需求的既可以展示 Jmeter 执行结果,又能让开发在线调试的页面。

Swagger UI

工欲善其事必先利其器,我先大致了解了一下 Swagger UI。
Swagger UI 是一个 API 在线文档生成和测试的框架。

优点

  • 方便测试人员和客户端开发了解 API
  • 页面简单直接,方便调试

着手本地部署

(1)下载 Swagger UI

git clone https://github.com/swagger-api/swagger-ui.git

(2)创建一个空文件夹mkdir swagger

(3)初始化,并创建 package.json 文件npm init

(4)安装 express

npm install express --save

(5)在 swagger 中创建目录 public,并将刚才 clone 下来的 Swagger UI 中 dist 目录下的所有文件全部复制到 public 目录下面。

(6)创建并修改swagger.js

var express = require('express');
var http = require('http');

// 接口显示页面
app.use('/static', express.static('public'));
app.listen(8005, function () {
  console.log('app listening on port 8005!');
});

(7)启动服务

cd swagger/
node swagger.js

打开http://127.0.0.1:8005/static/index.html,可以看到在线的官方的 Demo 已经在本地搭建好了。

改造之旅

第一步,希望替换官方的 API

需要用到 Swagger Editor 生成一个合格的 Swagger UI 依赖的 Spec。

可以通过Swagger Editor,当然我推荐是自己本地部署一个 Swagger Editor,因为官方的这个链接,虽然我的网络是有代理的,但是在使用过程中会连接中断,使用体验并不好。

插播一句 Swagger Editor 的本地部署

其实特别简单,git clone + npm intall

本地安装 Swagger Editor

git clone https://github.com/swagger-api/swagger-editor.git

npm install

启动本地的 Swagger Editor,http://127.0.0.1:3001,可以看到这样的页面。

当然这是官方的例子。

可以导出为 json 格式的文件(这是我们需要的最重要的产物)。

可以参考官方的文档,编写正确的符合格式的 Spec。OpenAPI-Specification

小贴士:因为我们部署的 Swagger UI 是 2.0 的版本,未使用 3.0 是因为,感觉 3.0 的源码我更看不懂。

配置 json 文件

将导出的 data.json 放置在swagger/public/data/下,并且修改一下swagger/public/index.html

if (url && url.length > 1) {
      url = decodeURIComponent(url[1]);
  } else {
      url = "/static/data/data.json";
}

重启node swagger.js,然后重新打开浏览器,可以看到自己根据服务端 API 编写的 API 文档。

第二步解决跨域问题

本地部署好 Swagger UI 之后,虽然生成的 curl 命令是正确的,但是点击try it out,返回值一直是no content,经过查阅确认是因为 JavaScript 存在的同源问题。那么怎么解决呢?

这里要感谢我同事的帮忙,帮忙一起解决了。

解决的思路:

在 swagger.js 中,封装了一个真正向服务端发请求的方法/getResponse

app.use('/getResponse', function(req, response){

    var headers = {
      'aa': req.headers.aa,
      'xx':req.headers.xx,
      'content-type': req.headers["content-type"]
    };

    if(req.query){
        path = req.path.replace('/getResponse', '')  + "?" + querystring.stringify(req.query)
    }else{
        path = req.path.replace('/getResponse', '')
    }
    var options = {
        hostname: config_data.host,
        path: path,
        headers: headers,
        method: req.method
    };

    var req = http.request(options, function(res) {
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
            response.send(chunk);
            console.log('返回值: ' + chunk);
        });
    });
    req.on('error', function(e) {
        console.log('problem with request: ' + e.message);
    });

    req.write(querystring.stringify(req.body));
    req.end();
});

在 public/swagger-ui.js 中,修改Operation.prototype.urlify = function (args, maskPasswords)

将 url 值替换,实现对请求的拦截。

var url = '/getResponse';

这样,Swagger UI 直接点击 try it out 之后,请求是先发到 node

swagger.js,然后由 swagger.js 再向服务端真实发出请求,再将返回值,塞给 Swagger UI 解析展示。

当然过程中有 body 不能解析的情况,需要安装库

npm install multer --save

并加入代码

var bodyParser = require('body-parser');
var querystring = require('querystring');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

这个时候,在 Swagger UI 页面点击 try it out,已然可以真正的请求成功,也能让开发开始在线调试 API 了。

Jmeter 执行结果显示

这里我其实走了取巧的方法,在生成的 Swagger Editor 中,如果配置如下,可以看到,Swagger Editor 中,我的配置是这样的

我将 tags 中加入了 Jmeter 执行的结果,在具体接口信息中,将 Summary 字段也变成了 Jmeter 执行的结果。

最后在 Swagger UI 界面可以查看这里的 json 文件展示的样式:

可以说,手动尝试部分已经全部走通了,需要做的是将 Jenkins 调度 Jmeter 执行生成的 jtl 传递给 Swagger UI。

将 Jmeter 执行结果传递过来

分两步:

  • 用 python 将 Jmeter 生成的 jtl,转化成我们需要的格式的 json,主要参照

    {
    "info": {
        "version": "0.0.0", 
        "title": "测试服务端API"
    }, 
    "tags": [
        {
            "name": "测试一下", 
            "description": "【Jmeter build result】PASS"
        }
    ], 
    "paths": {
        "/aa.aa.aa.json": {
            "get": {
                "parameters": [
                    {
                        "description": "自已", 
                        "default": "-1", 
                        "required": "是", 
                        "in": "query", 
                        "type": "INT64", 
                        "name": "fuid"
                    }
                ], 
                "produces": [
                    "application/json"
                ], 
                "tags": [
                    "测试一下"
                ], 
                "summary": "Jmeter result: true 2017-03-30 19:04:12", 
                "consumes": [
                    "application/x-www-form-urlencoded"
                ]
            }
        }
    }, 
    "host": "test.test.com", 
    "swagger": "2.0", 
    "schemes": [
        "https"
    ]
    }
    
  • 在 swagger.js 中编写一个 upload API,可以将上一步生成的.json 文件传递过来。

安装 multer 库

npm install multer --save

upload API


var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, __dirname + '/public/data/');
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname);
  }
});

// 上传.json文件接口
app.post('/uploads', upload.single('file'), function(req, res, next){
    var file = req.file;
    res.send({'status': 'UPLOAD SUCCESS'});
});

这个时候,在 Jenkins 执行 Jmeter 接口测试之后,将 data.json 传递给,Swagger UI,然后 Swagger UI 显示结果,并供客户端开发在线调试。

回顾一下

客户端开发的需求基本都能得到满足,可以在线调试,可以看到正确的可执行的 curl 命令,可以看到关于这个接口当前的执行情况。

当然我对 Node 的认识非常非常皮毛,临时看了点介绍,之前一点没有了解。可能有些地方有更好的实现方式,可是我没有了解到。

当然还有很多需要优化的地方:

ToDo:

  • 关于接口的更详细的描述和参数的描述需要添加
  • Response Body 开发希望看到可以选择显示格式的,比如 JSON | RAW | XML
  • 可以将 Paramters 部分参数固定可选的模式,现在是有默认值,可填,可随意修改

参考文档

Swagger UI 教程 API 文档神器 搭配 Node 使用 web api 接口文档 mvc 接口文档

基于 swagger 的 RESTful API 开发实践

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 21 条回复 时间 点赞

加精理由: 思路和技术都不错 分析问题的思路优秀 对相关技术也能深入研究并复用 可造之材

楼主,我在 swagger-ui.js 中并没有找到 Operation.prototype.urlify = function (args, maskPasswords),github 上的多个版本都没有找到,请问下你用的 swagger ui 的具体版本是多少?

您好我想问一下,您这里说的 var url = '/getResponse';是指您上面提到的函数里面的 url 吗?
另外还有一个问题,我写的这个 Api,没有基于任何 web 框架可以使用吗

您好,我想问一下我是在 window 本地部署的 swagger,但是并没有看到 swagger.js 这个文件,该如何解决跨域问题呢

挺有意思的一个思路

—— 来自 TesterHome 官方 安卓客户端

snake 回复

赞,我记录的并不完毕,我修改一下,谢谢

思寒_seveniruby 将本帖设为了精华贴 04月01日 11:36
徐旻 回复

真棒,我之前想的是用 flask 写个服务展示这个 spec,测试用例的管理也正好用 flask 定制,谢谢提醒

哈哈,谢谢夸奖。

不二家 回复

这个思路我也思考了很久了,不如加个好友,聊一聊。微信号:lunamagic1978

我觉得做好加上录制功能和单个 api 的 case 管理页面。
我说的录制功能就是当开发把调试时候他觉的对的 case 保存下来,以后跑自动化的时候可以直接用他的 case。
这样就带出了 api 的 case 管理页面,这个是个测试人员用的,这里可以编辑 case,然后点一个 run。 那么自动化的 api 回归测试就可以开了。
至少这样做测试不用去找开发要文档了。有什么,直接进入 case 页面,看参数,就很清楚了。

另外我的想法是用 django+swagger ,这样开发和测试可以通过 html 访问同一个资源,然后在运行 case 的时候自己写一个 request 的封装,到时候想怎么定制都可以。

@diao2007 安装的过程 6,7 两步,埋了几个坑。
第 6 步: 要加上 var app = express(); 都没定义,后面没法调用。
第 7 步: 我是把文件放项目的根目录运行起来的。

对这个挺感兴趣的,感谢分享

—— 来自 TesterHome 官方 安卓客户端

不太明白 jmeter 那里 你是用 jmeter 去跑 api 测试,然后把生成 jti 转成 swagger-ui 需要的 json 文件么? 这样不如直接用 supertest+jasmine+chai 编写脚本 用 jenkins 执行,如果成功 通过 js 直接修改对应成功的 json 来得直接,而且封装起来也简单 少了 jmeter 那一层。

qilei 回复

如你所说,我们最初只是拿 jmeter 做接口测试,没有想过用 swagger ui 展示,随着 jmeter 用例的增多,才想到展示的问题,因为不想放弃之前写的脚本,所以并未放弃 jmeter,你说的这 supertest+jasmine+chai 我还不太了解,我会研究研究,谢谢。

请教下作者,操作中其他的看明白了,jtl 转 json 那里没太看明白,jtl 放在哪里进行转换,用的什么,没看懂,求教谢谢。

不二家 回复

这个过程文中好像没有提,我查了下转换五花八门的,方便提供下 code 么?

不二家 回复

好的,我看下,谢谢指导!

jtl 是 jmeter 执行结果,其实是一个 xml,用 python 写的脚本转换,解析一下,就可以。

用 python 的库 ElementTree 解析 xml,很简单的。

是 jenkins 每次执行完都取解析一遍,不需要的 json 可以根据 key-value 值,key 值过滤。

18楼 已删除
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册