接口测试 改造 Anyproxy 录制生成 postman 测试用例及 fuzz

syl7752 · 2016年12月09日 · 最后由 syl7752 回复于 2016年12月16日 · 2303 次阅读

目的

  • 录制接口,生成验证响应的 postman 测试脚本
  • 可在 anyproxy 界面删除不需要的请求,不想在文件中删
  • 根据请求进行 fuzz,在界面可查看 fuzz 类型及响应状态

实现

导出

在 index.html 中增加导出选项

<a href="#"><span class="topBtn J_exportContainer"><i class="uk-icon-save"></i>Export</span></a>

增加导出界面 exportPanel.js

var ExportPanel = React.createClass({
        dealSave:function(){
            var self = this,
                userInput = React.findDOMNode(self.refs.pathInput).value;

            self.props.onExportCollection && self.props.onExportCollection.call(null,userInput);
        },      
        render:function(){
            var self = this;

            return (
                <div>
                    <h4 className="subTitle">Export Postman collection</h4>
                        <div className="exportSection">
                        <div className="uk-form">
                            <input className="uk-form-large" ref="pathInput" defaultValue={self.props.defaultValue} type="text" width="300"/>
                        </div></div>
                    <div className="exportSection-btn">
                                <button type="button" className="uk-button" onClick={self.dealSave}>Save</button>
                            </div>
                </div>
            );
        }
    });

效果如图

在 index.js 中处理对保存按钮的处理

var exportBtn = $(".J_exportContainer");
    exportBtn.on("click",function(e){
        e.stopPropagation();
        e.preventDefault();
        $.getJSON("getRootPath",function(resObj){
            var defaultPath = resObj.fullPath + "/default.postman_collection";
            var ExportPanel = PopupContent["exportP"];
            exportPanelEl = (<ExportPanel defaultValue = {defaultPath} onExportCollection={exportCollection} /> );
            showPop({ left:"60%", content:exportPanelEl });         
        });


    }); 

    function exportCollection(userInput){
        var data = {
            type: 'export',
            path: userInput, 
            data: showedIdSet
        }
        ws.send(data,function(){
            hidePop();
        });
    }

这里是将录制的请求 id 都通过 websocket 发送给后端,后端去做导出请求的操作.我想让使用 filter 后只导出过滤后的请求,所以在 filter.js 中记录了录制的 id,代码很少就不贴了
新建 collection.js 和 request.js,用于保存集合和请求,websocketServer 根据 id 查询 db 中的信息,返回 request 信息并添加到 collection 中

if (jsonData.type == "export") {
        var coll = new collection();
        async.forEach(jsonData.data, function(item, callback) {

            getRequestFromDB(item, coll.get().id, function(err, req) {
                coll.addRequests(req.get().id, req.getJson());
                callback();
            });
        }, function(err) {
            var filePath = jsonData.path;
            fs.writeFileSync(filePath, JSON.stringify(coll.getJson()));
        });
    }

生成返回值的验证代码

case '[object number]':
               st.push('//检查 ' + key + ', 类型是number, p = ' + p + ', key = ' + key + '\n');

               //检查存在该字段
               st.push('assertHasData(jsonData' + p + ',"' + key + '");\n');

               //检查字段类型是否符合
               st.push('tests["jsonData' + p + '.' + key + ' = "+ Object.prototype.toString.call(jsonData' + p + '["' + key + '"]).toLowerCase()] = Object.prototype.toString.call(jsonData' + p + '["' + key + '"]).toLowerCase()  == "[object number]";\n');

               //检查数值相等
               st.push('tests["jsonData' + p + '.' + key + ' = ' + data[key] + '"] = jsonData' + p + '["' + key + '"]  === ' + data[key] + ';\r\n');

               break;

我只验证的类型和值,如果想自定义,可修改 request 里的 parseToTestCode.至于 postman 脚本的格式,可在 postman 中导出查看文件格式
关于删除,是在表中新加了一列,代码可看源码,效果如图

生成的文件可导入 postman 使用或直接用 newman 执行

fuzz

修改了 requestHandler.js,录制到请求后,根据请求执行 fuzz 的 case,为不影响客户端,只返回原请求的 response

var cases = fuzzer.generater.generate(options,userRule.shouldRunFuzzTest());

    //get request body and route to local or remote
    async.each(cases, function(item, callback) {
        if (global.recorder) {
            path = item.path;
            resourceInfoId = global.recorder.appendRecord(resourceInfo);
            resourceIdList.push(resourceInfoId);
            item.resourceInfoId = resourceInfoId;
        }

        logUtil.printLog(color.green("\nreceived request to : " + host + path));
        fetchReqData(function() {
            routeReq(item, function() {
                callback();
            })
        });
    });

testCase 的格式如下,我只加了 11 条 case,如需要可在 fuzzer.js 中自定义

//no headers
var testCase1 = function(options) {
    var testOptions = clone(options)
    testOptions.description = "no headers";
    testOptions.headers = {};
    return testOptions;
}

添加支持参数"-F",为启动 fuzz 模式,详见 bin.js

整体改造完成,效果如下:

使用

node lib/bin.js

源码

https://github.com/syl7752/anyproxy

共收到 2 条回复 时间 点赞

阅读源码中,向您学习

向阳 用 anyproxy 记录移动端 UI 测试数据 中提及了此贴 09月27日 20:26
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册