如何编写有效的接口测试?

news2024/11/26 21:49:08

在所有的开发测试中,接口测试是必不可少的一项。有效且覆盖完整的接口测试,不仅能保障新功能的开发质量,还能让开发在修改功能逻辑的时候有回归的能力,同时也是能优雅地进行重构的前提。编写接口测试要遵守哪些原则?测试代码的结构应该是什么样的?接口测试有哪些实践技巧?本文分享作者在接口测试上的实践总结。

一线开发同学,可能都或多或少地造成过线上bug甚至故障; 也会遇到这样的场景,某同学在开发某功能的时候重构了代码,造成了线上bug或者故障; 在开发某个功能时,发现需要修改公共逻辑,害怕影响到其他功能,非常不雅观地拷贝代码,重新写套单独逻辑来支持。

上面这些情况,都包含了一个关键的问题,无论是功能开发还是逻辑重构,如何来保障代码开发的质量。保障的手段,每个人都知道,就是测试。首先是新功能测试,保障新功能逻辑正确;其次是回归测试,保障原有业务功能逻辑正确。测试的方式,一般是两种,人工测试和自动化测试。随着测试技术和工具的持续发展,人工测试比例逐步降低,被自动化测试逐步替代。自动化测试是可持续和可重复的,甚至是可AI化的。

一 测试分层

测试也是分层的,如下图所示:

在一个系统内,自动化测试一般分单元测试、模块测试和接口测试。

单元测试

目前我的应用代码基本都是基于spring框架面向接口这种编程模式,单元测试已被弱化。单元测试的要求基本上是单个类单个方法的测试,在我们当前模式下,编写成本太高。当然,如果是一个工具或者一段比较内聚而又复杂的逻辑(例如算法逻辑),还是应该使用单元测试来保障逻辑的正确性。

模块测试

在系统比较大、模块比较多的情况下,可以建立模块测试层,保障各模块功能的正确性。不过当前的系统发展趋势是微服务架构,因此模块测试层并非十分必要,可以通过接口测试层来覆盖。

接口测试

个人觉得准确来说应该叫入口测试,这一层,是从系统入口出发进行集成测试。应用入口通常是HSF (一个分布式RPC服务框架) 服务,消息,定时任务。

作为开发,测试手段千万条,接口测试不可少。在我们应用的接口测试有效且覆盖完整的情况下,不仅能保障我们新功能的开发质量,还能让我们在修改功能逻辑的时候有回归的能力,同时这也是我们做代码重构的前提。同时,易测性也是代码结构合理的一个指标,如果发现一段代码编写测试脚本困难或者无法测试,那就说明当前代码结构不合理需要重构。接下来,我将主要谈一谈接口测试的有效性。

二 测试原则

基础原则:

  • 自动化:接口测试是非交互式的自动化执行,不需要人参与。

  • 独立性:接口测试之间不应该相互依赖。

  • 可重复:接口测试可重复执行,不受环境影响。

  • 接口测试遵守BCDE原则,保障接口交付质量。

  • Border:边界测试。

  • Correct:正确的输入,正确的预期输出。

  • Design:按照需求和设计文档编写测试逻辑。

  • Error:错误输入,预期输出。

  • 数据准备:数据准备通过系统服务进行,不能通过直接插入db方式。

  • 可测性:对于不可测的代码需要进行重构成合理的结构。

  • 覆盖性:接口测试需要覆盖所有UC,同时代码覆盖率和分支覆盖率应达到一定标准,新增代码必须被覆盖。

  • 持续性:如果代码修改导致已有接口测试执行失败,必须修复代码问题或者测试代码逻辑。

  • 时间要求:接口测试应该在项目发布之前完成,不应放到项目发布之后补充。

以上的基本原则应适用于所有层的自动化测试用例,在编写接口测试时,除了上面这些原则,还有其他原则需要遵守,先看一张图:

从系统角度来分析入口调用,以 HSF 服务为例:

  • 外围系统调用由我们系统提供的服务。

  • 系统执行了一堆代码逻辑,其中包含有分支逻辑。

  • 系统执行过程中依赖外部 HSF 服务,进行了调用,并得到了返回值。

  • 系统执行过程中依赖DB查询或者落地了数据,依赖缓存查询或者落地了数据。

  • 系统执行过程中对外发送了消息。

  • 给上游系统返回 HSF 执行结果。

有效接口测试的关键原则是要覆盖所有入口,mock所有依赖,校验执行过程中所留下的痕迹,总结如下:

  • 入口覆盖:接口测试用例必须覆盖 HSF 服务入口、消息入口、定时任务入口。

  • 依赖mock:在基本原则中,有可重复这个原则,即接口测试不能受环境依赖,需要mock掉对外依赖。但对于db依赖,不建议完全mock掉,一方面mock成本高,另外可能覆盖不到sql和表约束逻辑。

  • 校验完整:有效的接口测试,应该具备完整的校验,没有校验的接口测试是没有意义的。只要执行过程中,留下的痕迹对业务有影响,都要进行完整校验,方能保障接口测试的有效性。

  • HSF 接口返回值校验:按照场景和接口约定进行 HSF 返回参数校验。

  • DB校验:校验落地数据的正确性。

  • 缓存校验:校验存入缓存中数据的正确性。

  • HSF 依赖入参校验:通过mock工具获得依赖 HSF 调用的入参,进行入参校验。

  • 消息校验:通过mock工具获得发送的消息对象,进行消息体校验。

三 测试代码结构

在编写测试代码的时候,也应跟写业务代码一样,考虑代码的可读、可扩展、可复用性。同时也可以根据系统的业务特性,在测试框架的基础上封装适合当前系统的测试组件,提高测试代码编写效率,规范测试代码结构。

一个接口的测试代码,大概的结构如下:

1 测试准备

依赖数据准备

很多时候,我们的测试有数据依赖,可能是配置数据,也有可能是业务数据(例如退款需要依赖支付数据)。

  • 配置数据:可以通过定义配置文件来初始化配置。

  • 业务数据:这类数据,禁止通过直接插入数据方式产生,而是应通过调用业务服务产生。

依赖mock

对于外部依赖,需要对被依赖的服务进行mock,避免真实调用。

接口测试入参准备

准备接口方面的入参。

2 测试执行

调用接口方法,执行业务逻辑。

3 测试校验

  • 返回参数校验:校验接口的返回参数。

  • DB:校验DB落地数据。

  • 缓存数据校验:校验落地到缓存中的数据。

  • 消息校验:校验对外发送的消息对象。

  • 对外 HSF 调用校验:校验对外 HSF 调用的入参。

四 实践技巧

1 执行效率

对于接口测试,执行效率是不得不关注的一个点,若一个接口测试执行3分钟以上才能看到结果,会大大降低开发同学编写接口测试的热情。对于测试执行效率提高,建议的方案为:

  • 最小化启动测试上下文,例如spring boot的应用,启动spring就可以了

  • 使用内存数据库,例如h2

  • 将中间件依赖mock掉

2 测试框架选择

对于测试框架,建议选择基于testng,能够提供通过配置文件做数据准备的测试框架。如果找不到合适的,可以自己基于testng进行封装。

3 接口测试覆盖度

场景的完整性影响着测试用例的覆盖度,一方面需要开发同学基于业务场景的输入和测试经验枚举出正常和异常情况,另一方面接口方法也有一些固定需要测试的点,例如幂等测试,边界值测试,参数不正确测试等等。

同时也要通过覆盖率工具查看接口未覆盖的代码或分支逻辑,进行针对性的场景覆盖测试。根据我的经验,分支完整覆盖非常重要,特别是异常的分支。

五 总结

要保障系统线上运行稳定,质量保障手段必不可少。虽然现在有很多自动化的保障手段,但接口测试依然是最基本的和最重要的保障手段之一。如能做到持续保障接口测试覆盖度和有效性,很大程度上会降低线上bug的产生,开发同学也会更有积极性去重构代码。

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/643443.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

unity Ignis - Interactive Fire(完美模拟:森林火灾、草原火灾、建筑火灾)

Ignis 可以把任何物体、植被或带皮带骨的网状物转换为可燃物体,它就会自动着火。然后,火焰可以蔓延,点燃其他物体,被粒子或光线熄灭,或者自然烧尽。也可以被粒子点燃。还会收到风力影响WindZone。 WindZone文档&#…

轻量级性能测试工具 wrk 如何使用?

项目设计之初或者是项目快要结束的时候,大佬就会问我们,这个服务性能测试的结果是什么,QPS 可以达到多少,RPS 又能达到多少?接口性能可以满足未来生产环境的实际情况吗?有没有自己测试过自己接口的吞吐量&a…

磁盘详解(一文搞懂磁盘)

目录 一.磁盘的结构 二.磁盘的分类 2.1按照磁头是否可以移动分类 2.2按照盘片是否可以更换分类 三.磁盘的读写过程 四.磁盘的调度 4.1FCFS先来先服务算法 4.2SSTF最短寻找时间优先 4.3 SACN扫描算法 4.4C-SACN循环扫描算法 4.5 SPTF(最短定位时间优先&…

Maxwell安装使用

​欢迎光临我的博客查看最新文章: https://river106.cn 1、Maxwell简介 Maxwell 是由美国Zendesk开源,用Java编写的MySQL实时抓取软件。读取 MySQL binlogs 并将修改行字段的更新写入 Kafka, Kinesis, RabbitMQ, Google Cloud Pub/Sub 或 Redis (Pub/Sub or LPUSH)…

基于Aidlux的停车标志检测(可修改为coco 80类目标检测)

●项目名称 基于Aidlux的停车标志检测(可修改为coco 80类目标检测) ●项目简介 本项目在Aidlux上部署检测停车标志检测,并可在源码上修改coco 80类目标检测索引直接检测其他79类目标,可以直接修改、快速移植到自己的项目中。 ●…

【学习笔记】Java——消息队列kafka

kafka 1、Kafka combines three key capabilities:2、kafka是如何工作的:3、Kafka APIS:4、kafka集群 1、Kafka combines three key capabilities: To publish (write) and subscribe to (read) streams of events, including co…

中国游戏等“春”来

对于游戏行业来说,2023年将是压力依旧的一年,但或许也是转型调优的希望之年。 压力在于,互联网流量见顶,用户付费意愿降低,行业整体进入下行周期,彻底进入存量竞争时代。《2022年中国游戏产业报告》显示&a…

相机标定实战之双目标定

相机标定原理 文章目录 相机标定原理前言一、采集图像二、基于Matlab单双目标定流程采集棋盘图 三、基于OpenCV-Python双目标定流程检测棋盘格角点对角点进行亚像素精细化单目标定双目标定双目校正保存标定参数读取标定参数代码示例 参考 前言 相机标定可以说是计算机视觉/机器…

哪个公司的 CEO 不想拥有一个自己的数字克隆?

⚠️ FBI Warning:本文纯属作者自娱自乐,数字人的观点不代表 CEO 本人的观点,请大家不要上当受骗!! 哪个公司的 CEO 不想拥有一个自己的数字克隆? 想象🤔一下,如果 CEO 数字克隆上线…

python基础语法总结

1.打印输出 print(“Hello World”) 在许多大众的编程语言中,需要在每个语句的末尾添加分号,但Python并非如此。Python是一种简洁的编程语言,你不需要添加不必要的字符和语法。在Python中,一条语句结束于一行的结尾(方括号&…

找不到msvcp120dll,无法继续执行代码的修复方法

本教程操作系统:Windows系统、 msvcp120.dll是电脑文件中的dll文件(动态链接库文件)。如果计算机中丢失了某个dll文件,可能会导致某些软件和游戏等程序无法正常启动运行,并且导致电脑系统弹窗报错。 msvcp120.dll文件…

IDEA整合GO并创建module工程

IDEA整合Go 安装包环境配置idea配置并创建test mode 安装包 1.去官网下载对应还的安装包 官网下载地址 我选择下载的window 版本: 直接按照对应的目录,然后点击下一步 环境配置 1.配置go环境变量 在高级环境变量PAHT中添加安装包的**/bin 目录&…

mysql数据库的基础

mysql数据库 一、数据库的基本概念二、关系数据库三、SQL语句增改查删 四、natvicat for mysql软件 一、数据库的基本概念 数据(data) 描述事物的符号记录包括数字、文字、图形、图像、声音、档案记录等以“记录”形式按统一的格式进行存储 表&#x…

基于Java少儿编程网上报名系统设计与实现(源码+lw+部署文档+讲解等)

博主介绍: ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ 🍅 文末获取源码联系 🍅 👇🏻 精…

sizeof 和 strlen !!!

定义 sizeof()是单目操作符,是可以求变量(类型)所占空间的大小,不在乎内存中存放的是什么,只在乎内存大小 strlen()是函数,是计算字符串的长度的 它从内存的某个位置(可以是字符串开头&#x…

进程管道:pipe调用

在看过高级的popen函数之后&#xff0c;我们再来看看底层的pipe函数。通过这个函数在两个程序之间传递数据不需要启动一个shell来解释请求的命令。它同时还提供了对读写数据的更多控制。pipe函数的原型如下所示&#xff1a; #include <unistd.h> int pipe(int pipefd[2])…

OS的事件机制-Event

Event在OSEK OS中&#xff0c;其实就是一个flag的作用&#xff0c;如果某个TASK执行了&#xff0c;就调用<SetEvent()>把flag就置起来&#xff0c;和这个task关联的另一个TASK也执行了&#xff0c;就可以把flag清掉<ClearEvent>&#xff0c;如果第一个TASK没有执行…

这才是你想了解的Redis

文章简介 redis作为一个基于内存的数据结构存储系统&#xff0c;由于它的灵活性和可拓展性强&#xff0c;在我们日常开发中经常被用作数据库、缓存或者消息代理。本文就从Redis的基本部署使用说到Redis的集群、锁和消息对列 Redis基本使用 一、安装 下载地址&#xff1a;htt…

mySql 储存过程 多个结果返回解析

当需要查询复杂的数据模型并返回多个结果集时&#xff0c;使用 MySQL 存储过程可以有效地优化性能。同时&#xff0c;在开发中使用 Mybatis 可以方便地调用 MySQL 存储过程并获取多个结果集。本文将介绍如何在 Mybatis 中调用 MySQL 存储过程&#xff0c;并获取多个结果集。 1、…

Java并发之原子类

一、原子类简介 1 什么是原子类 Java中提供了一些原子类&#xff0c;原子类包装了一个变量&#xff0c;并且提供了一系列对变量进行原子性操作的方法。原子性的意思是对于一组操作&#xff0c;要么全部执行成功&#xff0c;要么全部执行失败&#xff0c;不能只有其中某几个执…