本文为内部分享文档,意在从基础到深入分享单接口测试及系统接口测试内容。
此文借鉴和引用了多位同行的文章内容,均已标注内容来源。大家可通过链接查看相关内容原文。
测试的第一目标是质量保障,所以我们从质量保障的纬度,来了解接口测试。
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、如何测试接口
接口测试,主要分三步:
- 准备测试数据(可能不需要);
- API 测试工具,发起请求;
- 验证返回结果的 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 这类极度敏感的信息不应该所有人都有权限获取;
- 减少代码泄漏的危害性:假如代码出现泄漏,敏感数据信息不应该也同时泄漏。
-
推荐的解决方案:
- 对服务器进行权限管控,只有运维人员(或者核心开发人员)才有登录服务器的权限;
- 运维人员(或者核心开发人员):在运行的机器上将敏感数据设置到系统的环境变量中;
- 普通开发人员:只需要知道敏感信息的变量名称,在代码中通过读取环境变量的方式获取敏感数据。
如何构造数据
调用开发接口
直接使用 sql:就是直接写 sql 创造和销毁数据。
优点:隔离性和 bug 追踪都很好。
缺点:如果交给测试人员在脚本中写 sql 的话,难度,可读性都不太乐观,而且太依赖测试人员本身的能力,出错率较高。不过好在我们可以在测试框架上做一些手脚,解决这个问题。
使用建议:除查询 sql 外,增删改 sql 慎重使用,因为实现成本高、操作风险高。需要非常了解数据库表结构和业务逻辑,删改数据很可能影响实际业务或其他同学测试。
数据模版:为核心业务测试数据,创建独立的数据模版,专人独立维护。
参考:测试能效平台的诞生 - 国际化商城智能物料平台 · TesterHome
-
实现思路:
- 对于数据构造较复杂,且数据关联业务多、异常数据风险高的数据(比如电商的物料数据),建议基于开发接口封装通用函数,且针对性的做好异常处理和定位。
-
优点:
- 专人开发维护,极大降低构建复杂数据成本和风险
- 降低功能测试构造数据精力,突破相关测试人力占用瓶颈。
缺点:开发成本高,使用重量级业务系统
4、接口测试进化
回顾一下前面接口测试的内容,发现几个问题:
- 复杂系统动则几千个接口,回归测试工作量大;
- 用例编写成本高,参数多的接口
可以参考如下几个案例,对接口测试做一些生产力的提升。
(1)回归测试工作量大?录制线上流量回归
参考:录制线上流量做回归测试的正确打开方式 · TesterHome
(2)用例编写成本高?通用接口自动测试方案
参考:通用性接口健壮性扫描方案 - 有赞
(3)快速校验接口数据结构变化?接口自动化全量字段校验
来源:接口自动化全量字段校验 · TesterHome
实现:自定义接口返回数据格式 (【契约定义】)-实际响应数据格式校验 (【契约校验】) 的功能
校验原则:
- 实际返回字段名要严格等于或者含契约定义字段名 (根据不同匹配模式来确定)
- 字段值可以值相等或类型相等
↙↙↙阅读原文可查看相关链接,并与作者交流