接口测试过程中,当接口版本发生变更时,如何快速进行 diff 测试?本文使用 Node.js、Python、Java 三种语言来讲解如何快速的进行接口 diff 测试.
通过对接口返回结果添加断言来判断不同版本接口返回值是否相同,结合测试框架动态生成测试用例(测试数据参数化)来批量对比接口返回值。
测试过程中常用命令:
# 创建node.js项目
npm init
# 安装依赖包
npm install request mocha chai mochawesome --save
# 执行测试用例,并指定报告为mochawesome,报告默认存放到当前项目 mochawesome-report/ 目录中
mocha test\batchdiff.test.js --reporter mochawesome
测试过程中常用命令:
# 安装依赖包
pip install requests pytest pytest-html
# 执行测试用例,并生成html报告,报告指定存放到当前项目 static/ 目录中
pytest test\test_batchdiff.py --html=static\jsondiff.html
本地测试项目为 maven 项目,maven 依赖包如下:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.49</version>
</dependency>
<dependency>
<groupId>com.github.kevinsawicki</groupId>
<artifactId>http-request</artifactId>
<version>6.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.22.0</version>
</dependency>
maven 命令:
# 运行测试用例
mvn test
# 运行测试用例,生成html报告,报告默认存放到项目的 target/site 目录中
mvn surefire-report:report
测试用例运行效果
html 报告
源代码
var assert = require('chai').assert;
var request = require('request');
describe("Node.js版本批量接口diff", function () {
this.timeout(0);
[
// diff apis
{
"oldapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/demo",
"newapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/demo"
},
{
"oldapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/hello",
"newapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/hello"
},
{
"oldapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/user",
"newapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/user"
},
{
"oldapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/1/list",
"newapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/1/list"
},
{
"oldapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/2/list",
"newapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/2/list"
},
{
"oldapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/3/list",
"newapi": "https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/3/list"
},
].forEach(function (kv) {
it(kv.newapi + " vs " + kv.oldapi, function (done) {
request.get(kv.newapi, {
json: true
},
function (err, res, body) {
request.get(kv.oldapi, {
json: true
},
function (oldapiError, oldapiRes, oldapiBody) {
assert.deepEqual(body, oldapiBody);
done();
}
);
}
);
});
});
});
测试用例运行效果
html 报告
源代码
# -*- coding:utf-8 -*-
import unittest
import requests
from parameterized import parameterized, param
diffApis = [
# diff apis
{
"oldapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/demo",
"newapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/demo"
},
{
"oldapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/hello",
"newapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/hello"
},
{
"oldapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/user",
"newapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/user"
},
{
"oldapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/1/list",
"newapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/1/list"
},
{
"oldapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/2/list",
"newapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/2/list"
},
{
"oldapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/3/list",
"newapi":"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/3/list"
},
]
class TestParameterized(unittest.TestCase):
@parameterized.expand(
[param("diff test",kv) for kv in diffApis])
def test_batchdiff(self, _, kv):
self.maxDiff = None
oldRes = requests.get(kv["oldapi"])
newRes = requests.get(kv["newapi"])
self.assertDictEqual(oldRes.json(), newRes.json())
if __name__ == '__main__':
unittest.main(verbosity=2)
html 报告
源代码
package com.test.apitest;
import com.alibaba.fastjson.JSON;
import org.junit.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.github.kevinsawicki.http.HttpRequest;
public class BatchDiffTest {
@DataProvider
public Object[][] data() {
Object[][] diffApis = new Object[][]{
{
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/demo",
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/demo"
},
{
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/hello",
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/hello"
},
{
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/user",
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/user"
},
{
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/1/list",
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/1/list"
},
{
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/2/list",
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/2/list"
},
{
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v1/3/list",
"https://easy-mock.com/mock/5b6b06f9a40bfb27425bbb6a/jsondiff/v2/3/list"
},
};
return diffApis;
}
@Test(dataProvider = "data")
public void test_apiDiff(String oldApiUrl, String newApiUrl) {
String oldJsonString = HttpRequest.get(oldApiUrl)
.accept("application/json")
.body();
String newJsonString = HttpRequest.get(newApiUrl)
.accept("application/json")
.body();
Object oldJsonVo = JSON.parseObject(oldJsonString);
Object newJsonVo = JSON.parseObject(newJsonString);
Assert.assertEquals(oldJsonVo, newJsonVo);
}
}
命令行日志显示的对比结果
当接口返回结果不一致时:
1) mocha+chai 断言在日志中显示效果最好,日志输出 json 字段级别不一致的地方;
2) python+unittest 断言在日志中显示的是 python dict 对象,不太友好;
3) java+junit 仅在日志中显示两个对比的对象不一致,需要借助 IDE 对比返回值字段级别不一致的地方;
html 报告
与命令行输出日志相似,当接口返回值不一致时:
1) Node.js 体系的 mochawesome 报告最好看,最直观,可以看到 json 字段级别不一致的地方;
2) Python 体系的 pytest-html 报告 diff 测试结果不友好,不能明显看出 json 字段级别不一致的地方;
3) Java 体系的 Surefire Report 不能看出 json 不一致的地方;
中文支持
Node.js、Java 语言输出日志、html 报告中中文字符正常显示为中文字符,python 输出日志、html 报告中中文字符显示为中文字符对应的 Unicode 编码
各种测试框架都有官方文档,从官方文档中可以获取到参数化的知识,下述参考资料仅供参考.
本文发布于个人微信公众号 发现 Bug,欢迎关注。