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

diao2007 · 2017年03月31日 · 最后由 menging 回复于 2018年06月14日 · 11923 次阅读
本帖已被设为精华帖!

前言

接口测试是自动化测试过程中,投入产出比相对而言比较大的工作,我们组之前一直在用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开发实践

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

挺有意思的一个思路

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

seveniruby 将本帖设为了精华贴 04月01日 11:36

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

seveniruby 回复

哈哈,谢谢夸奖。

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

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

lunamagic 回复

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

diao2007 回复

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

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

snake 回复

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

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

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

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

qileilove 回复

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

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

wxhhxx123 回复

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

diao2007 回复

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

wxhhxx123 回复

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

diao2007 回复

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

18楼 已删除

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

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

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

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