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

恒温 · 2021年03月16日 · 最后由 扎扎辉 回复于 2022年08月31日 · 8430 次阅读

zz from 阿里巴巴技术质量,AlibabaTechQA,阿里巴巴 QA 官方技术号,呈现阿里巴巴质量领域最新的技术发展和创新。

一线开发同学,可能都或多或少地造成过线上 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 的产生,开发同学也会更有积极性去重构代码。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 10 条回复 时间 点赞

不错,加精了

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

这个不太明白,假如我要退款,肯定是要支付数据的,支付数据从其他接口调度获取?那退款接口就需要二次调支付接口产生支付数据,这与你前面说的 ‘接口测试之间不应该相互依赖’ 不是相矛盾吗? 还是说我理解错了😅

sun 回复

😂

sun 回复

我觉得关于业务数据不能插库的很好理解,比如你要生成一笔支付数据,直接插入数据库,如果有多表关联、缓存或者消息队列的逻辑,一旦写漏了容易产生脏数据,还比较费时,所以直接调用接口是最省事的,也最符合系统行为;关于 ‘接口测试之间不应该相互依赖’ 这点,我觉得应该是 ‘接口测试用例之间不应该相互依赖’,有要重复使用的需要封装成方法或者关键字。

整个接口测试的基础,是不是需要相个独立的测试环境,但往往绝大部分公司都没有这个环境。

所以只有玩的起的公司才会这么玩。万事都是要成本的。

完全和我们现在的策略一模一样。。。不过你描述起来就是比我高大上很多呀~
补充个,对于资源不够的项目,用例执行完得考虑下数据清理和还原。

但是还有附带的一些其他内容:接口元数据,文档类等关联项的好像没有,可能不仅仅涉及接口测试了

这个接口测试是开发同学做的接口测试吗?感觉好专业,还要自己搭框架,我们测试的做的接口测试太水了

兔子🐰 [该话题已被删除] 中提及了此贴 02月18日 16:23
sun 回复

我对这个也有疑问;比如一个业务流程,提交数据-》审核 1-》审核 2;那对于审核 1 的接口而言,它的前提条件是需要有提交的数据,对于审核 2 接口而言,它需要有审核 1 的数据;如果要测审核 2 这个接口,要么插库生成对应的数据,要么调前面的接口,如果调前面的接口生成,是不是审核 2 接口又依赖前面的接口了呢?

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