news 2026/5/14 6:10:17

一个基于多接口的业务自动化测试框架

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一个基于多接口的业务自动化测试框架

这是一个成熟的框架,不是要让别人当小白鼠,它已经先后在两家公司的5条业务线进行了推广应用,用例条数到了几千条以上,并且从2018年开始每天都在CI/CD流程中被调用执行。

已有那么多接口测试框架,为什么重复造轮子?首先,本框架如题目描述,适用于多接口的业务自动化测试,不是简单的接口测试框架;其次框架始于2017、2018 年,当时也没有现在如此多的接口测试框架。

代码地址:https://github.com/HzlGauss/bulls

框架介绍

接口自动化测试无疑是测试提效最为行之有效的方案,市面上的接口自动化测试框架很众多,而本框架与其它框架的区别如以下:

  • 用例代码编写简单,让使用者精力集中在所测试系统的业务逻辑上,而 http 接口的定义,请求的发送,测试报告信息等都由框架完成;

  • 不只适用于单个接口的测试,同样适用于多个接口组成的完整的业务逻辑的测试,这往往是接口自动化测试更应该做到的;

  • 登录等前置的业务操作也由框架完成,用例中只需引用相应 cookie;

  • 框架同样支持环境、各类账号以及其它测试物料信息维护;

  • 简单易用,java 小白也能在半小时内学会使用。

框架结构

上手指南

工程结构说明

下面是一个论坛登录、浏览帖子、帖子点赞这样一个简单的业务场景进行举例,如何用框架完成这一几步操作的。

定义http接口

接口定义是在 yml 文件中,建议按照被测系统维护 yml 文件

  1. api:

  2. globalVariables:

  3. - UA: "Mozilla/5.0(Macintosh;IntelMacOSX10_13_6)AppleWebKit/537.36(KHTML,likeGecko)Chrome/81.0.4044.138Safari/537.36"

  4. pioneers:

  5. - name: testerhome登录

  6. id: testerhomeLogin

  7. priority: 1

  8. path: https://$testerhomeHost/account/sign_in

  9. method: post

  10. headers: >-

  11. \{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8","User-Agent":"$UA","x-requested-with":"XMLHttpRequest",

  12. "cookie":"user_id=eyJfcmFpbHMiOnsibWVzc2FnZSI6Ik1UVTJOamM9IiwiZXhwIjpudWxsLCJwdXIiOiJjb29raWUudXNlcl9pZCJ9fQ%3D%3D--43f5d4f117b5459e67c85cc6c569820abb1e6068; _homeland_session=Y2ljEAtdhRcbEHaTSSHMb3%2FUyn0aLrFrHoEP8QVjVq%2BvXMCEi9n57WDgHBw40L%2Bo%2Fghe148%2B%2B429DbYDWNAiC4FBFYFnEghtzkQWPpKsOm21DZQkUDLvYqr4Z2ylpkiGHqjpppkhw0LLke61psEh7ZKQte3Ia3TTzTSu9ifDtHEl9FBlZUXNgwi%2F5kscioZqkobTyJpCGp5M4mSrLiunIZUHbgm05AuWa5%2Bu2TwgsxOfpdAumg6Q0SoT7ipMLaGaprobuP0Kj2q5ZH4CKqG7fb%2FU0WwzsTgTCtMXaWLz5WYHizGKRD5CWysSMseGn5I%3D--5LouY27EpiVkGarr--tpTXhgdFShw4Qyn6sThkpg%3D%3D",

  13. "x-csrf-token":"zr6fgSyPS5nyqcwGdzD7R6T51aAK6L9Dv42Lao0CSPZo4jEn3pT5fNN2eTk84VdmqhzQasF+sdHQrvvxsLYSmg=="\}

  14. parameters: user[login]=&user[password]=&user[remember_me]=0&user[remember_me]=1&commit=登录

  15. extractors: \[{"name":"token","value":"cookies"}\]

  16. requests:

  17. - name: 读帖子

  18. id: topics

  19. path: https://$testerhomeHost/topics/38484

  20. method: get

  21. headers: >-

  22. \{"User-Agent":"$UA","Content-Type":"application/x-www-form-urlencoded","cookie":"$token","x-requested-with":"XMLHttpRequest","x-csrf-token":"r3E8899sEAEnqST2dmtIEluqG5C/nL/Rwp2l4ITtNDU3XpF4eULhClMRoWweMt6XWSmBn2H8fmPRas+CVkA/BA=="\}

  23. - name: 点赞

  24. id: likes

  25. path: https://$testerhomeHost/likes

  26. method: post

  27. headers: >-

  28. \{"User-Agent":"$UA","Content-Type":"application/x-www-form-urlencoded","cookie":"$token","x-requested-with":"XMLHttpRequest","x-csrf-token":"r3E8899sEAEnqST2dmtIEluqG5C/nL/Rwp2l4ITtNDU3XpF4eULhClMRoWweMt6XWSmBn2H8fmPRas+CVkA/BA=="\}

  29. parameters: type=Topic&id=38484

如上,接口定义文件大体分为三部分:globalVariables,pioneers,requests。

  • globalVariables:定义全局变量,为key、value形式

  • pioneers 定义前置接口,用于定义登录等前置接口。程序启动后、用例开始执行前,会自动先执行pioneers中定义的接口。其中name随意起;id 要唯一,建议按照接口请求地址的缩写命名id属性;priority,整数类型,当pioneers中定义了多个接口,执行时会按照priority属性排序,之后顺序执行。extractors:接口返回内容的提取,name,为提取的变量命名,后面接口可以通过 $name 名对其进行引用;value,变量的提取内容,支持提取cookie或返回json字符串中的某个属性 (填写属性的json path)

  • requests定义接口,基本同pioneers部分,少了extractors部分。

说明:此处的接口请求参数可以通过抓包工具抓包获取,然后复制到这里。接口定义只需定义一次,在用例中随意获取,使用接口时,根据需要设置请求参数,未设置的请求参数按照此处定义的值作为默认值。

用例代码:
  1. @Test(enabled = true, description = "打开帖子详情页→点赞")public void test() {

  2. log.info("test start");

  3. //请求实例1,打开帖子详情页

  4. Request request = Request.getInstance("topics");

  5. //请求1发送

  6. Response response = request.doRequest();

  7. //返回为html,取其中的x_csrf_token,后面点赞接口用

  8. String html = response.asString();

  9. Headers headers = response.getHeaders();

  10. Map<String, String> cookies = response.getCookies();

  11. Document document = Jsoup.parse(html);

  12. Element metaElement = document.select("meta[name=csrf-token]").first();

  13. String x_csrf_token = null;

  14. if (metaElement != null) {

  15. x_csrf_token = metaElement.attr("content");

  16. }

  17. //请求实例2,点赞接口

  18. request = Request.getInstance("likes");

  19. //更新cookie

  20. request.addCookies(cookies);

  21. if (x_csrf_token != null) {

  22. request.addHeader("x-csrf-token",x_csrf_token);

  23. }

  24. //发送点赞请求

  25. response = request.doRequest();

  26. assertThat(response.getStatusCode()).isGreaterThanOrEqualTo(200).as("返回状态码校验");}

测试报告

如下图,用例相关接口的请求信息、返回信息也都由框架自动记录在了报告中,如有其它需要内容输出到测试报告,可以在用例中添加 Report.log("要添加内容")。

其它
  • 配置:如其它 spring 工程,配置文件在 resources 目录下,类似 pre、test 区分不同环境,application.properties 中定义一般的配置信息(和环境无光),其中 pring.profiles.active=pre 来切换不同环境

  • 测试范围定义:测试用例由testng维护,如框架中所示,详细使用方法参见testng官网(https://testng.org/doc/documentation-main.html#testng-xml)

    1. <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" ><suite verbose="1" name="bulls-test" ><listeners>

    2. <listener class-name="com.bulls.qa.service.CustomListener"></listener>

    3. <listener class-name="com.bulls.qa.service.NoticeListener"></listener></listeners><test name="bulls自动化" preserve-order="true">

    4. <parameter name="reruntimes" value="0"></parameter>

    5. <packages>

    6. </packages>

    7. <classes>

    8. <class name="com.bulls.qa.testcase.testerhome.Demo">

    9. <methods>

    10. <include name="test"></include>

    11. </methods>

    12. </class>

    13. </classes></test></suite>

    运行:项目入口 com.bulls.qa.BullsApplication.main

  1. //打包

  2. mvn clean -DskipTests=true package

  3. //运行

  4. java -jar target/bulls-0.6-SNAPSHOT.jar 测试范围配置文件.xml

AI写代码

如上面例子,测试范围配置文件可以配置多个,执行时指定测试范围,如不指定默认使用打包的程序代码中的测试范围配置文件

  • 测试报告:测试报道为单html文件,方便jenkins配置展示,报告地址运行时所在目录下bulls.html

  • 断言,选用的断言框架为 AssertJ,AssertJ 的强大无需赘述,详细使用方法参见 AssertJ 官网(https://assertj.github.io/doc/)

assertThat(response.jsonPath().getList("recommendations")).size().isGreaterThan(0).as("recommendations长度大于0");assertThat(response.jsonPath().getBoolean("has_more")).isTrue().as("has_more为true");assertThat(response.jsonPath().getList("recommendations")).as("recommendations长度大于0").size().isEqualTo(3);List<String> types = JsonPath.from(response.asString()).getList("recommendations.item_type");String[] strs = "product,product-ad-card,deal,ad,shopping-curated-collection,auto-generated-collection,video,campaign-banner,benefit,web-view".split(",");assertThat(strs).containsAll(types).as("types在枚举范围内");
  • 发送测试结果消息通知,参见代码 NoticeListener,具体根据需要自行扩展

  • 接口传参设置,较复杂的接口参数设置

相关接口定义

  1. - name: 编辑商品

  2. id: itemEdit

  3. path: http://$mnghost/item/edit

  4. method: post

  5. cookies: $XXXXXXCookies

  6. headers: >-

  7. \{"User-Agent":"$UA","Content-Type": "application/json"\}

  8. parameters: >-

  9. \{"itemId":"2904"\}- name: 添加商品

  10. id: itemSave

  11. path: http://$mnghost/item/save

  12. method: post

  13. cookies: $XXXCookies

  14. headers: >-

  15. \{"User-Agent":"$UA","Content-Type": "application/json"\}

  16. parameters: >-

  17. \{"itemId":"2913","categoryIdList":[1],"topCategoryName":"美食","itemName":"autoTest goods","limitNumber":3,

  18. "priceText":"","countDownCycle":"3","countDownLimit":"1","itemNo":"12sqw","delivery":"MANUAL",

  19. "image":"//yun.XXXXXX.com/images/202005/4su03vvahd.jpg","detail":"","itemStatus":"ON","skuProperties":[],

  20. "skuList":[{"id":3375,"stock":999999,"stockId":null,"sellingPrice":100,"originalPrice":100,"costPrice":100,

  21. "realPayPrice":100,"properties":null,"skuNo":"1","skuEnable":true,"changeStock":0}],"supportCOD":true,

  22. "originItemId":null,"merchantId":73,"tagIds":[],"id":2913,"topCategoryId":1,"itemShortName":"autoTest goo","url":null,

  23. "minPrice":100,"stock":0,"isRecommend":false,"minSkuOriginalPrice":null,"minSkuPriceDiff":null,"maxPriceDiff":null,

  24. "maxPriceDiffPrice":null,"maxPriceDiffOriginalPrice":null,"gmtModified":"2020-06-19 16:57:36","gmtModifyName":"测试专用",

  25. "gmtModifyEmail":"test@XXXXXX.com.cn","mainRecomIds":null,"merchantName":"autoTestShop01","merchantDelivery":"MANUAL",

  26. "imgHeight":[{"imgUrl":"http://yun.XXXXXX.com/images/202006/mj3yg07pj8.jpg","height":136},

  27. {"imgUrl":"http://yun.XXXXXX.com/images/202006/d47ad68hhc.jpg","height":372}],"mainImgUrl":null,"itemIntroduce":null,

  28. "saleLableUrl":null,"ssoDesc":null\}

相关代码

  1. goodsId = 2904;//编辑接口,获取测试的商品信息Request request = Request.getInstance("itemEdit");//直接设置,key-value形式Response response = request.setParameter("itemId", goodsId).doRequest();//库存小于50,更新库存JsonPath jsonPath = response.jsonPath();if (jsonPath.getBoolean("success") && jsonPath.getInt("data.stock") >= 50) {

  2. // dosomething}Map<String, Object> map = response.jsonPath().getMap("data");if (map == null) {

  3. map = new HashMap<>();}map.put("itemId", goodsId);map.put("stock", 9999999);request = Request.getInstance("itemSave");//遍历接口的传参结构定义,替换掉key完全匹配的那个map部分request.setParameters(map);//按照json path定位要设置的keyrequest.setParameter("$.skuList[0].stock", 9999999);request.setParameter("$.skuList[0].changeStock", null);//根据路径删除,路径按json pathrequest.removeParameterByPath("$.skuList[0].stockId");request.removeParameterByPath("$.skuList[0].id");request.doRequest();

  • 详尽的json-path使用方法,参见JsonPath使用(https://www.javadoc.io/doc/io.rest-assured/json-path/latest/io/restassured/path/json/JsonPath.html)

感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 2:45:34

2025最新9个降AI率工具测评,本科生必看

2025最新9个降AI率工具测评&#xff0c;本科生必看 2025年降AI率工具测评&#xff1a;为什么你需要这份榜单&#xff1f; 随着高校和科研机构对AIGC内容检测的愈发严格&#xff0c;越来越多本科生在论文写作中遭遇“AI率超标”的问题。不少学生发现&#xff0c;仅仅依靠简单的同…

作者头像 李华
网站建设 2026/5/2 16:02:29

2026最新软件测试面试题(带答案)

1. 请自我介绍一下(需简单清楚的表述自已的基本情况&#xff0c;在这过程中要展现出自信&#xff0c;对工作有激情&#xff0c;上进&#xff0c;好学) 面试官您好&#xff0c;我叫###&#xff0c;今年26岁&#xff0c;来自江西九江&#xff0c;就读专业是电子商务&#xff0c;毕…

作者头像 李华
网站建设 2026/5/11 15:56:49

本地大模型部署难题,Ollama + Open-AutoGLM组合真的能一键解决吗?

第一章&#xff1a;本地大模型部署难题&#xff0c;Ollama Open-AutoGLM组合真的能一键解决吗&#xff1f;在本地部署大语言模型&#xff08;LLM&#xff09;长期面临环境配置复杂、依赖冲突频繁、显存管理困难等痛点。传统方式需手动编译源码、配置Python虚拟环境、安装CUDA驱…

作者头像 李华
网站建设 2026/5/4 6:19:30

学长亲荐9个AI论文工具,专科生毕业论文轻松搞定!

学长亲荐9个AI论文工具&#xff0c;专科生毕业论文轻松搞定&#xff01; AI工具助力论文写作&#xff0c;专科生也能轻松应对 对于许多专科生来说&#xff0c;撰写毕业论文无疑是一项既紧张又复杂的任务。面对繁重的写作压力和时间限制&#xff0c;如何高效地完成一篇结构严谨、…

作者头像 李华
网站建设 2026/5/3 15:19:34

2025大模型一体机全攻略:从技术选型到行业落地实战指南

《大模型一体机应用研究报告》全面解析了这一"硬件软件模型应用"的全栈集成系统&#xff0c;涵盖定义特点、四大行业实践案例、六步选型法及未来趋势。报告显示2025年市场规模将突破千亿&#xff0c;2027年有望达5000亿元&#xff0c;为政企提供智能化转型的实用指南…

作者头像 李华
网站建设 2026/5/6 7:31:12

Open-AutoGLM本地部署性能优化秘籍(提升3倍响应速度的4种方法)

第一章&#xff1a;Open-AutoGLM本地部署概述Open-AutoGLM 是一个开源的自动化代码生成与语言建模框架&#xff0c;支持基于自然语言描述生成高质量代码片段。本地部署该系统可确保数据隐私、提升响应速度&#xff0c;并便于与企业内部开发流程集成。部署过程涉及环境准备、依赖…

作者头像 李华