测试基础 服务端接口测试指南

在路上 · 2021年05月08日 · 最后由 陈辉 回复于 2022年05月17日 · 34628 次阅读
本帖已被设为精华帖!

本文为内部分享文档,意在从基础到深入分享单接口测试及系统接口测试内容。

此文借鉴和引用了多位同行的文章内容,均已标注内容来源。大家可通过链接查看相关内容原文。

测试的第一目标是质量保障,所以我们从质量保障的纬度,来了解接口测试。

1、了解接口

1.1 接口做了哪些事?

首先,从功能角度理解。
比如,从一个用户购买一个商品的业务流程来理解:

  • 新用户注册:通过注册接口 新增一条用户数据(Create);
  • 注册成功后登录:通过登录接口,首先根据用户名查询(Select)密码,然后校验密码,密码校验成功,通过规则和加密 新建(Create)token 签名,将 token 发送给客户端;
  • 搜索商品:通过商品搜索接口搜索目标商品,本质是从商品数据库中进行条件查询(Select);
  • 查看商品详情:商品 ID + 商品详情接口,查询商品详情(Select);
  • 选择商品加入购物车:添加购物车接口,更新购物车数据,库存数据减一(Update);
  • 创建地址并选择地址:新建地址接口,新增一个新的地址(Create);
  • 下单&结算:下单接口,新增一条新的订单数据(Create);
  • 支付:支付接口,如果支付成功,新增一条支付信息,订单状态更新为已支付,新增一条物流信息。

接口的功能主要是客户端和服务端的数据交互,即通过接口对后端数据的增删改查,来实现用户和产品的交互。

1.2 如何保障接口质量

从京东网站的注册接口来看,我们需要从哪些纬度保障质量。

分析注册接口

注册页面:

Http 注册接口:

Request Header:

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Content-Length: 6028
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Cookie: shshshfpb=sJZnAsUTcZJjuNedVMhztBA%3D%3D; 
Host: reg.jd.com
Origin: https://reg.jd.com
Referer: https://reg.jd.com/reg/person?ReturnUrl=https%3A//www.jd.com/
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36
X-Requested-With: XMLHttpRequest

Request Body:(忽略部分无法解读参数)

uuid: 68455e864c894bda845de413849204d0
authCodeStrategy: 1  (验证码策略)
phone: +00861553605xxxx(手机号)
mobileCode: 116547(手机验证码)
regName: demo83520(注册的用户名)
email: xxx@163.com(注册邮箱)
mailCode: 661591(邮箱验证码)
pwd: MvaEqtzkZ4/R4P3wMoRIuZpA4egWYBmz7bikspIWRYwozJgOHJQlQW8POp8elFhi7OXchoz1OPRoFwxqjWpwcWQCUABx5oovhFxLZ0p8CqB3s0lNDz9QlF8ZYMBanwk+Cne4mXMOTop9OGD8XF8YPqb4qkox8A=(密码加密字符串)

接下来,从接口开发设计角度,分析注册接口。因为是纯黑盒角度,所以从 UI 交互和接口参数两方面分析注册接口的设计逻辑。

UI 交互角度分析

  • 同样手机号、不同邮箱最多可以注册 3 个账号;
  • 用户名:支持中文、英文、数字、” - “、”_” 的组合,4-20 个字符,不能是纯数字;用户名不能重复;
  • 密码:长度只能在 8-20 个字符之间,建议使用字母、数字和符号两种及以上组合;不能频繁注册;

接口参数分析(取几种主要参数)

  • uuid:用户唯一 ID?uid 生成规则?
  • phone:注册手机号格式校验?
  • mobileCode:手机验证码位数、字符类型校验?
  • regName:用户名规则校验?
  • email:注册邮箱格式校验?
  • mailCode:邮箱验证码 位数、字符类型校验?
  • pwd:密码加密后字符串

2、如何测试接口

接口测试,主要分三步:

  1. 准备测试数据(可能不需要);
  2. API 测试工具,发起请求;
  3. 验证返回结果的 Response;

(1)测试数据

测试数据生成方式:

  • 基于 API 生成数据;
  • 数据库直接构造数据;
  • UI 操作生成数据;

生成时机:

  • 实时创建:测试用例执行过程中生成(会导致测试用例执行时间变长);
  • 事先创建:测试执行前,批量生成所有测试数据(可能事先创建好的数据已经被修改而无法正常使用);

注意⚠️:测试环境不稳定,会影响测试数据的顺利创建;

脏数据:

  • 概念:脏数据是指,数据在被实际使用前,已经被进行了非预期的修改。

测试数据分类:

  • “死水数据”:指相对稳定,不会在使用过程中改变状态,并且可以被多次使用的数据。这类数据适合事先创建。
    • 注意:“死水数据” 是相对稳定的,是否稳定由测试目的决定。比如用户数据,在测试非用户相关测试时基本稳定,但是对于专门测试用户账号的测试用例来讲,往往涉及到用户注销之类功能,所以此时就是不稳定的。
  • “活水数据”:指只能被一次性使用,或者经常会被修改的数据。例如 优惠券、订单之类的数据。

(2)测试用例设计

用例设计从两个维度来设计,功能性需求和非功能性需求。

功能性需求

用例设计法参考:软件测试基础—流程和用例设计方法-piecesof

非功能性需求 - 安全纬度

  • 敏感信息是否加密:密码前后端传输是否加密
  • sql 注入?(结合用户的输入数据动态构造 Sql 语句,如果用户输入的数据被构造成恶意 Sql 代码,Web 应用又未对动态构造的 Sql 语句使用的参数进行审查,则会带来意想不到的危险。)
  • 逻辑漏洞:
    • 批量注册重复消费问题?(比如,同一时间,同样的参数,高并发请求,是否只有一个 Http 请求注册成功)
    • 同一手机号,不同邮箱,是否可以注册超过 3 个用户?

非功能性需求 - 性能纬度

功能性需求纬度:利用正交法,最少也有 29 条用例。
非功能性需求纬度 - 安全纬度:4 条用例。
非功能性需求纬度 - 性能纬度:2 条用例。

(3)如何做接口断言?

  • Http Response 断言:
    • Http 状态码
    • Response Body 字段、结构 校验
    • Response Header
  • 数据断言:
    • 对数据库中的数据断言
  • 响应时间满足要求吗?

3、如何用接口测试一个系统?

(1)复杂系统测试用例结构

参考:HttpRunner 之 step/case/suite

测试步骤 (testStep) -> 测试用例 (testCase) -> 测试场景/测试用例集 (testSuite)

测试步骤 (testStep)

对于接口测试来说,每一个测试步骤应该就对应一个 API 的请求描述。

测试用例 (testCase)

测试用例(testcase)应该是为了测试某个特定的功能逻辑而精心设计的,并且至少包含如下几点:

  • 明确的测试目的
  • 明确的输入
  • 明确的运行环境
  • 明确的测试步骤描述
  • 明确的预期结果

测试用例设计原则:

  • 测试用例应该是完整且独立的,每条测试用例都应该可以独立运行;
  • 测试用例由测试脚本和测试数据两部分构成。
  • 测试脚本:测试脚本只关注被测的业务功能逻辑,包括前置条件、测试步骤、预期结果等。
  • 测试数据:是对应测试的业务数据。
  • 测试数据和测试脚本分离:方便实现数据驱动测试。通过对测试脚本传入一组数据,实现同一业务功能在不同数据逻辑下的测试验证。比如:购买商品接口,会员和非会员的商品价格是不一样的,优惠券逻辑也不一样。所以通过不同的用户数据,可以测试会员和非会员购物逻辑。

测试用例集 (testSuite)

测试用例集是测试用例的无序集合,集合中的测试用例应该互相独立,不存在先后依赖关系。

如果确实存在先后依赖关系,例如登录功能和下单功能。正确的做法应该是,在下单测试用例的前置步骤中执行登录操作。

(2)测试数据管理

来源:孙高飞 - 测试框架中的数据管理策略

数据的两个属性:

  • 作用域:共享数据(适用于 testSuite 级别)、隔离数据(适用于 testCase 级别)
  • 创建方式:调用开发接口、使用 Sql、独立开发数据模版

测试数据的作用域

共享数据:所有 case 或一部分 case 共同使用的测试数据

  • 优点:速度快,数据只需要创建一次就可以给很多 case 使用。
  • 缺点:
    • 数据为很多 case 准备的,你很难分清哪些数据是给这个 case 准备的,哪些数据是给另一个 case 准备的。case 的可读性低
    • case 之间互相有影响。因为待测的功能本身就会对数据库造成影响。很可能一个 case 的失败或者成功就会造成一批 case 的 fail
    • 数据本身不能扩展,稍微一改动,影响就很广泛。数个甚至数十个 case 的失败是很常见的。维护脚本的成本比较高

隔离数据:每个 case 都有独享测试数据,case 之间互不影响,即每个 case 都做 setup 和 teardown 的操作。case 执行前创造数据,执行后销毁数据。

  • 优点:case 之间互不影响,数据之间互不影响。case 的稳定性,可维护性,可读性等都大大提高
  • 缺点:速度慢。。。。灰常慢。。。因为每个 case 都有很多的磁盘 IO 操作。。。维护数据的时间比调用功能的时间都要长的情况并不奇怪。 OK,这种方式其实是我们在测试中运用的最多的方式。虽然它很慢,而且对很多人来说实现起来也比较难。但是它带来的可维护性实在太诱人。我再也不用整天维护那些不稳定的脚本了。慢点就慢点吧。反正我们做接口测试和 UI 自动化测试的持续集成策略也是定时运行的。 跑个 10 几分钟,几十分钟的我也不在乎。 只要不是做监控代码变动的策略,一切好说。

敏感数据:账号、密码、key 等敏感信息,设置为有权限限制的环境变量。

  • 敏感信息不能公开的主要原因:

    • 加强权限管控:参与项目的开发人员可能会有很多,大家都有读取代码仓库的权限,但是像 key 这类极度敏感的信息不应该所有人都有权限获取;
    • 减少代码泄漏的危害性:假如代码出现泄漏,敏感数据信息不应该也同时泄漏。
  • 推荐的解决方案:

    • 对服务器进行权限管控,只有运维人员(或者核心开发人员)才有登录服务器的权限;
    • 运维人员(或者核心开发人员):在运行的机器上将敏感数据设置到系统的环境变量中;
    • 普通开发人员:只需要知道敏感信息的变量名称,在代码中通过读取环境变量的方式获取敏感数据。

如何构造数据

调用开发接口

  • 优点:在脚本中实现起来相对简单,不用深入理解后台数据库。
  • 缺点:

    • 耦合性太高,依赖产品的其他接口创造数据的方式注定了 case 是非隔离性的。注意隔离性是 case 质量的一个重要指标。一旦创造数据的接口 bug 了,你说得有多少个 case 失败。而且在真实环境中,需要调用 N 个接口去创造你需要的数据。无法判断到底哪个接口的 bug。这已然变成了端到端测试了。能够快速定位 bug 位置,也同样是 case 质量的重要指标。
    • 如果做隔离数据,产品中的接口往往很难满足你销毁数据的需要,举个最常见的例子。这个世界存在一种删除机制叫做逻辑删除,也是就是产品的接口并不是真正的删除了数据库中的数据,而是用一个逻辑标示位,标示这条数据被删除了。不要再反馈给用户了。 这样其实就做不到 “隔离数据了”
  • 使用建议:不建议使用。虽然该方式脚本维护成本低,但是造成用例耦合度高、隔离性差,问题定位成本高。一个被调用开发接口的 BUG,可能会导致大量用例失败。

直接使用 sql:就是直接写 sql 创造和销毁数据。

优点:隔离性和 bug 追踪都很好。
缺点:如果交给测试人员在脚本中写 sql 的话,难度,可读性都不太乐观,而且太依赖测试人员本身的能力,出错率较高。不过好在我们可以在测试框架上做一些手脚,解决这个问题。
使用建议:除查询 sql 外,增删改 sql 慎重使用,因为实现成本高、操作风险高。需要非常了解数据库表结构和业务逻辑,删改数据很可能影响实际业务或其他同学测试。

数据模版:为核心业务测试数据,创建独立的数据模版,专人独立维护。

参考:测试能效平台的诞生 - 国际化商城智能物料平台 · TesterHome

  • 实现思路:

    • 对于数据构造较复杂,且数据关联业务多、异常数据风险高的数据(比如电商的物料数据),建议基于开发接口封装通用函数,且针对性的做好异常处理和定位。
  • 优点:

    • 专人开发维护,极大降低构建复杂数据成本和风险
    • 降低功能测试构造数据精力,突破相关测试人力占用瓶颈。
  • 缺点:开发成本高,使用重量级业务系统

4、接口测试进化

回顾一下前面接口测试的内容,发现几个问题:

  • 复杂系统动则几千个接口,回归测试工作量大;
  • 用例编写成本高,参数多的接口

可以参考如下几个案例,对接口测试做一些生产力的提升。

(1)回归测试工作量大?录制线上流量回归

参考:录制线上流量做回归测试的正确打开方式 · TesterHome

(2)用例编写成本高?通用接口自动测试方案

参考:通用性接口健壮性扫描方案 - 有赞

(3)快速校验接口数据结构变化?接口自动化全量字段校验

来源:接口自动化全量字段校验 · TesterHome

实现:自定义接口返回数据格式 (【契约定义】)-实际响应数据格式校验 (【契约校验】) 的功能

校验原则:

  • 实际返回字段名要严格等于或者含契约定义字段名 (根据不同匹配模式来确定)
  • 字段值可以值相等或类型相等
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 31 条回复 时间 点赞

学到了,谢谢分享。

Thirty-Thirty 回复

这个回帖打💯分

renven1 回复

客气啦

学到了,谢谢分享。

感谢关注

已收藏😁

wu 回复

🍻

10楼 已删除
dxx4396 回复

过奖啦

豁然开朗

生成时机的第三点没太看懂,是有错别字吗

Gregory 回复

不好意思,因为内容有误,已修复

贴主是知识厚积薄发了,如此有深度的知识写的小白也简单易懂,期待后续继续分解相关知识

构造数据这一块儿楼主是怎么做大呢,个人观点还是调用开发接口比较好,因为不熟悉开发表结构,有看过别人的教训,整个关联表自行插入都有问题,导致出现奇怪 bug

红客联盟 回复

写操作,一定不能直接操作表。

  • 写操作:建议调用开放接口
  • 读操作:可以直接查询数据库
恒温 将本帖设为了精华贴 06月03日 06:35

写的太好了,谢谢大佬分享

Thirty-Thirty 回复

牛逼👍 ,我们的测试平台的接口测试模块的实现思路以及很多想法跟你文中提到的很多点都不谋而合,厉害厉害

toString139 回复

谢谢支持

总结了很多东西,实际方案中基本上都能用到,这篇文章看完读懂,小白面试也不怕了

解决了我最近纠结的很多点,感谢

@ 蔓藤不到冬 @ 清风的故事 客气啦,能帮到大家就好

前半段很容易懂,后半段我就得思考思考了

锤锤 回复

可以的

后半段没做过,线上流量回放这种,不知所以然

你好,你的文字中的博客链接显示 404

斯派克 回复

可以在 404 页面的文章列表中找到想看的文章。

或者,去主页搜索:

太精彩了!

如何应对接口变更,而导致的大量用例的修订呢,这方面一直不知道如何有效的降低修订成本,在一个产品还不稳定的情况下,面对的基本都是新的接口,在迭代过程中经常会有接口字段的变动,有什么维护的建议吗

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