接口测试 http (s) 接口自动化测试框架 (基于 java)

sen · 2017年03月21日 · 最后由 hong 回复于 2018年10月24日 · 7759 次阅读

http(s) 接口自动化测试框架 (基于 java) 介绍

使用 java(jdk8)+maven+httpclient+testng+reportng+poi+jsonpath,可集成 jenkins。
java(jdk8)+maven+httpclient+testng 就不做介绍了,reportng 只是为了报告好看,修改了部分源码,poi 用于读取存放于 excel 的接口用例,jsonPath 用于校验返回值,以及提取返回值。
想直接查看源码的可以直接访问:http 接口自动化测试

一言不合上 demo

配置:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <rootUrl>http://apis.baidu.com</rootUrl>
    <headers>
        <header name="apikey" value="123456"></header>
    </headers>
    <params>
        <param name="test" value="value"></param>
    </params>
</root>

用例设计如下:

用例

接口执行的总体情况:

执行结果

接口执行的具体详情:

用例详情

详细介绍

环境

demo 中的用例以百度的 api store 为例(具体查看:百度 api 商城

运行

  1. IDE 工具直接执行 testng.xml(以 testng 形式运行) 即可(ide 工具需要先装好 testng 插件)。
  2. maven 执行:mvn test.

执行报告查看

  1. testng.xml 执行可视化报告:${workspace}/test-output/html/index.html(IDE 工具需要设置 testng 全局监听器配置:org.uncommons.reportng.HTMLReporter)
  2. maven 执行报告:${workspace}/target/surefire-reports/html/index.html

api-config.xml 配置

api 请求根路径、请求头及初始化参数值可以在 api-config 上进行配置。

rootUrl: 必须的配置,api 的根路径,在调用 api 时用于拼接,配置后,会在自动添加到用例中的 url 的前缀中。

headers: 非必须配置,配置后在调用 api 时会将对应的 name:value 值设置到所有请求的请求头中 header-name:header-value。
params:非必须配置,公共参数,通常放置初始化配置数据,所有用例执行前,会将 params 下所有的 param 配置进行读取并存储到公共参数池中,在用例执行时,使用特定的关键字 (${param_name}) 可以获取。具体使用请参考下面的高级用法。

<root>
    <rootUrl>http://apis.baidu.com</rootUrl>
    <headers>
        <!-- 换成自己实际的值 -->
        <header name="apikey" value="123456"></header>
    </headers>
    <params>
        <param name="param1" value="value1"></param>
    </params>
</root>

api 用例 (case/api-data.xls)

api 请求用例具体数据。除表头外,一行代表一个 api 用例。执行时会依次从左到右,从上到下执行。

  • run:标记为 ‘Y’ 时,该行数据会被读取执行。
  • description:该用例描述,在报告中提现。
  • method:该 api 测试用例的请求方法(暂只支持 get,post)。
  • url:该 api 测试用例的请求路径。

说明:
若配置文件 (api-config.xml) 中 rootUrl 为:http://apis.baidu.com ,url 的值为:/apistore/aqiservice/citylist ,框架执行的时候会根据配置文件中 rootUrl 进行自动拼接为:http://apis.baidu.com/apistore/aqiservice/citylist
若填写 url 填写为 http 作为前缀的值如:http://www.baidu.com/s?w=test 将不会进行拼接。

  • param:请求方法为 post 时,body 的内容(暂只支持 json,不支持 xml)。
  • verify:对于 api 请求 response 数据的验证(可使用 jsonPath 进行校验)。校验多个使用 “;” 进行隔开。

说明:
若 verify 填写值为:$.errorCode=0;$.errorMessage=success ,则会校验返回值中 $.errorCode 的值为 0,$.errorMessage 的值为 success,只要有一个校验错误,后面的其他校验项将停止校验。

  • save:使用 jsonPath 对 response 的数据进行提取存储。

说明:
若 save 值为:id=$.userId;age=$.age ,接口实际返回内容为:{"username":"chenwx","userId":"1000","age":"18"},则接口执行完成后,会将公共参数 id 的值存储为 1000,age 存储为 18。公共参数可在后面的用例中进行使用。具体使用方法见下方高级用法。

高级用法

测试用例 excel 表中可以使用 ‘${param_name}’ 占位符,在执行过程中如果判断含有占位符,则会将该值替换为公共参数里面的值,如果找不到将会报错。如:

//配置文件(api-config.xml)中params配置为:
<params>
    <param name="apikey" value="123456"></param>
</params>

//A用例执行返回为
{"username":"chenwx","userId":"1000","age":"18"}
//A用例的save值为:
username=$.username;id=$.userId

//此时若B用例中param值填写为:
{"key":"apikey","userId":"${id}","username":"${username}"}
//实际执行时会替换为:
{"key":"123456","userId":"1000","username":"username"}

函数助手

测试用例 excel 表中可以使用 ‘__funcName(args)’ 占位符,在执行过程中如果判断含有该占位符,且 funcName 存在,则会执行相应的函数后进行替换。先支持函数如下:

  • __random(param1,param2):随机生成一个定长的字符串 (不含中文)。param1:长度 (非必填,默认为 6),param2:纯数字标识 (非必填,默认为 false)。
  • __randomText(param1): 随机生成一个定长的字符串 (含中文)。param1:长度 (非必填,默认为 6)
  • __randomStrArr(param1,param2,param3):随机生成一个定长字符串数组。param1:数组长度 (非必填,默认为 1),param2:单个字符串长度(非必填,默认 6),param3:纯数字标识 (非必填,默认为 false)。
  • __date(param1): 生成执行该函数时的格式化字符串。param1 为转换的格式,默认为 ‘yyyy-MM-dd’。
  • __generateStrArrByStr(param1,param2):生成定长的字符串数组。param1:参数为数组长度 即生成参数个数,param2:字符串
  • __sub(param,params...):减数。第一个参数作为减数,其他参数均作为被减数。
  • __max(params...) 获取所有参数的最大值。
  • __plus(params...) 将所有参数进行相加。//参数中其中有一个包含小数点将会返回带小数点的值
  • __multi(params...) 将所有参数相乘。
  • __bodyfile():。
//若param中值为:
{"username":"__random(6,true)"}
//实际执行时,username的值会替换为长度为6的数字随机数如:
{"username":"653495"}

待优化

  • 支持 xml
  • 支持 auth
  • 支持 delete,put 等方法
  • 支持验证数据库
  • 待加 +++++

最后,欢迎拍砖,吐槽,有兴趣的可以关注我的公众号。

关注公众号

共收到 38 条回复 时间 点赞

你应该是用 JAVA 写的,如有可能,试用一下 zson:https://github.com/zhangfei19841004/zson
不甚感激!😃

2楼 已删除
sen #3 · 2017年03月21日 Author
再见理想 回复

jsonPath 也是很强大的呢!几乎支持所有 json 的取值😆

sen 回复

zson 也是,如有可能,请尝试一下!

sen #5 · 2017年03月22日 Author
再见理想 回复

写法还是跟 jsonPath 的写法不同哈,替换的话成本太大了,毕竟这套东西在我司内部已经有几千个用例在跑了😂 ,不过互相学习也是好的。😄

我用的是阿里 fastjson 里提供的 jsonPath 包,原因强大是一方面,另一个方面是有人更新维护。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.13</version>
</dependency>

可以用 extentreport

sen #7 · 2017年03月22日 Author
Anson 回复

好像不错的样子,也有人推荐使用 Allure,我研究看看😆

再见理想 回复

😂 我在试用你的 zson,语法挺简单,我觉得你可以试着上传到官方 maven 库上

这个整合,除了报表,核心部分比用 java-assured 好在哪?
java-assured 本身已经有 json 和 xml 的处理封装。

sen #10 · 2017年03月22日 Author
Anson 回复

之前没有接触过 java-assured,所以直接用 httpclient 了,刚才查了一下好像 java-assured 很是强大,学习学习先!😆

CC 回复

多谢支持!语法简单,功能强大专一强大!考虑丢到 maven 官方库上。要是有什么问题也可以跟我提!

clone 了代码到 IDEA,执行时报错, 是怎么回事。。

api_autotest\conf\env\email-config-112.xml (系统找不到指定的路径。)
sen #14 · 2017年04月13日 Author
Mr_Peace 回复

不好意思,提交了其他版本的代码,已经修复。

你好,可以分享源代码吗,这个框架的,O(∩_∩) O 谢谢

sen #16 · 2017年04月20日 Author
wuliguaiguai 回复

源码在文章前面的说明里面有阿!

直接报错,什么情况

java.io.FileNotFoundException: E:\otherProject\api_autotest (拒绝访问。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.(FileInputStream.java:138)
at java.io.FileInputStream.(FileInputStream.java:93)
at com.sen.api.utils.ExcelUtil.readExcel(ExcelUtil.java:73)
at test.com.sen.api.TestBase.readExcelData(TestBase.java:255)
at test.com.sen.api.ApiTest.readData(ApiTest.java:96)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:564)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:213)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)
at org.testng.TestRunner.beforeRun(TestRunner.java:641)
at org.testng.TestRunner.run(TestRunner.java:609)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1198)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1123)
at org.testng.TestNG.run(TestNG.java:1031)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:124)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

java.lang.RuntimeException: 转换 excel 文件失败:E:\otherProject\api_autotest (拒绝访问。)

at com.sen.api.utils.ExcelUtil.readExcel(ExcelUtil.java:83)
at test.com.sen.api.TestBase.readExcelData(TestBase.java:255)
at test.com.sen.api.ApiTest.readData(ApiTest.java:96)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:564)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:213)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)
at org.testng.TestRunner.beforeRun(TestRunner.java:641)
at org.testng.TestRunner.run(TestRunner.java:609)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1198)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1123)
at org.testng.TestNG.run(TestNG.java:1031)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:124)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

sen #18 · 2017年04月21日 Author

最近提交的代码有点问题,已经修复。请重新获取代码。

如场景是:登录 (生成 token)--》查询请求, 但这请求需要再 head 加入 token, 请问这个框架可以实现吗?
根据这场景进行扩展, 可以支持自定义加入 head 的场景吗?

菠萝蜜 回复

你只有自己改造下了

sen #37 · 2017年06月12日 Author
菠萝蜜 回复

暂不支持执行过程动态加入 head。不过支持共用 cookies,不知道这样能否满足你的需求。

我下载了您的代码部署到了本地,使用 get 方法没问题 可是使用 post 方法,返回的信息一直是传入参数为空,URL、参数格式都没错(postman 验证通过),这是为什么呢?求解。

sen #23 · 2017年10月09日 Author
胡尔查 回复

可以通过报告中得 log 查看具体调用信息。或者可以提供给我是怎么设置参数的。

sen 回复

找到原因了 谢谢你!

@chen_sen excel 中的 param 格式什么什么样的,我弄成 json 格式的怎么老是不行呢

胡尔查 回复

我这的 post 的也不行,传入的参数显示为空,你那怎么解决的?

咖啡咖 回复

我的是在 header 中加入这个即可解决:

<header name="Content-Type" value="application/json"></header>

请问楼主,我想在 api-config.xml 的 headers 中传入动态 token 参数,例如执行一个用户登录的测试用例后,response 返回一个 token 值,我想将这个值保存为全局参数然后传到 header 的 token 值中,然后,之后的每次测试,这个 token 值都会动态刷新。请问是否可以实现?如何实现?谢谢!

sen 回复

“支持共用 cookies”,这个是如何实现的呢?

sen #30 · 2017年11月03日 Author
咖啡咖 回复

或许要设置请求头,你可以通过报告看下实际发送的数据

sen #31 · 2017年11月03日 Author
胡尔查 回复

这个可以实现,可以自己拓展支持,后续的版本我会加上

32楼 已删除

看到这个 excel, 多么熟悉, 和我之前搞的框架一模一样,哈哈,加油

胡尔查 回复

我的加上 header 后,form-data 还是拿不到,找不到问题所在

sen #35 · 2017年12月20日 Author
咖啡咖 回复

可以加我好友,看截图应该是没问题才对。chen5xian

sen #36 · 2017年12月20日 Author
matt gong 回复

😂

请问下,我要跑的接口都是不同的 HOST,xml 配置文件里的 rootUrl 该怎么写?我用你相同 host 的接口都没问题,不同 host 的不知道怎么解决

zongqi 回复

支持在用例里写死路径

太好,最近正在自学 java 接口自动化,可是发现没有书籍可以参考,还好发现了你的文章,谢谢!

还会再更新吗?

请问报告中文乱码是什么原因

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