如何在 Apifox 的 API 测试中使用数据库查询(MySQL、MongoDB、Redis)

绿色的状态码也会撒谎!本文详解如何在接口测试中引入数据库操作,教你在测试中直连MySQL、Redis等数据库进行数据初始化、数据断言与下游传参,打破黑盒限制,验证磁盘上的真实数据。

用 Apifox,节省研发团队的每一分钟

如何在 Apifox 的 API 测试中使用数据库查询(MySQL、MongoDB、Redis)

免费使用 Apifox

相关推荐

最新文章

API

一体化协作平台

API 设计

API 文档

API 调试

自动化测试

API Mock

API Hub

立即体验 Apifox
目录

绿色的状态码也会撒谎。你的 POST /orders 接口返回了 201 Created,响应 body 看起来完美无瑕,测试也通过了。但是,这一行数据真的以正确的状态写入数据库了吗?库存数量减少了吗?如果测试只读取 HTTP 响应,那么它只能验证 API 声称做了什么,而不是系统实际做了什么。要弥补这一差距,你必须直接查看数据库。

这正是测试场景中数据库查询的价值所在。你可以在请求发送前初始化(seed)一个已知状态,发送请求,然后查询数据表以确认磁盘上的真实数据。Apifox 通过内置的“数据库连接”和“数据库操作”处理器支持了这一功能,因此你可以在驱动 HTTP 调用的同一个场景中,将运行 SQL 或 NoSQL 命令作为其中的步骤,而无需编写外部脚本来进行衔接。如果你是第一次构建场景,关于如何使用 Apifox 编写测试场景的指南涵盖了本文所基于的请求级基础知识。如果你想温习关系型存储如何对这些数据进行建模,MDN 的服务端概述是一个不错的入门教程。

在测试中引入数据库操作能带来什么价值

从不触及数据库的 API 测试就像是一个黑盒。它完全信任响应。在大多数情况下这没问题,但那些棘手的 Bug 往往存在于 API 返回的内容与它持久化保存的内容之间的差距中:比如一个状态字段从未更新、一个外键指向虚无,或者本该是软删除的操作却变成了物理硬删除。

数据库步骤可以帮你做到纯 HTTP 测试无法完成的三件事:

  • 初始化(Seed) 精确的初始状态,使测试不受残留数据的影响。
  • 对比真实数据进行断言,通过读取 API 声称已写入的数据行来进行验证。
  • 从数据库中提取真实的值并将其传递给下一个请求,这样你的测试就可以使用服务端实际生成的 ID,而不是凭空猜测。

Apifox 将该功能分为两步。首先,在“设置 > 数据库连接”下创建一个可重用的连接。然后,将“数据库操作”步骤作为“前置操作”(在请求之前运行)或“后置操作”(在请求之后运行)关联到请求上。一个连接可以在项目中的每个场景里重复使用。

在你开始规划之前,需要注意一下支持范围。MySQL、SQL Server(2014 及更新版本)、PostgreSQL 和 Oracle 支持免费版。ClickHouse、MongoDB 和 Redis 则需要付费版。MongoDB 文档明确指出:连接到 MongoDB 是一项付费功能。Redis 也是如此。因此,下面关于 MySQL 的实操演示可以在免费版上运行,而 MongoDB 和 Redis 部分则需要付费方案。

步骤 1:创建数据库连接

打开“设置 > 数据库连接”,然后点击右上角的 + 新建。选择你的数据库类型,然后填写连接信息字段:

  • 数据库地址(例如 db.staging.internal127.0.0.1
  • 端口(MySQL 默认为 3306
  • 用户名密码
  • 数据库名(例如 shop

如果您的数据库位于堡垒机后面,请展开 SSH Tunnel 区域并添加跳板机详情。MySQL 还支持 SSL 模式,并提供四个选项:Prefer(默认,先尝试 SSL 连接,失败则回退)、RequireVerify CAVerify Full。请选择您的服务端支持的最严格的选项,然后点击保存

以下两个连接注意事项可以帮您避免一下午的困惑:

  • MySQL 8 auth:默认的 caching_sha2_password 插件可能会拒绝连接。如果遇到 auth 错误,请使用 ALTER USER 'tester'@'%' IDENTIFIED WITH mysql_native_password BY '...'; 切换用户的身份验证方式,然后重试。MySQL 参考手册 深入介绍了插件之间的差异。
  • 凭证保存在本地:连接详情存储在您自己的机器上,不会同步到云端。每位团队成员都需要自己配置连接。如果您正在进行团队协作,关于共享数据库连接设置的说明会详细解释该工作流。

步骤 2:使用前置操作填充数据

假设您正在测试订单创建流程。您希望在下订单之前存在一个已知的客户,这样测试就不会依赖于表中当前存在的任何随机数据。

打开您的请求,找到前置操作,将鼠标悬停在添加数据库操作上,然后选择数据库操作。将其命名为 seed customer 之类的名称,选择您的 MySQL 连接,然后在 Enter SQL Command 下编写一条插入语句。动态变量使用 {{variable_name}} 语法,因此您可以直接从环境获取变量值:

INSERT INTO customers (id, email, status)
VALUES ({{customer_id}}, '{{customer_email}}', 'active')
ON DUPLICATE KEY UPDATE status = 'active';

现在,请求在确定的状态下运行。客户已存在,处于活跃(active)状态,并且其 ID 已为后续步骤所知。在前置操作中填充数据可以保持每个测试的独立性,而不会受测试顺序带来的副作用影响。

步骤 3:使用后置操作对数据库进行断言

这就是核心部分。您的请求会创建一个订单。在其返回响应后,您查询 orders 表以确认该行存在且状态正确。

添加调用您的 API 的请求:

POST /api/orders
Content-Type: application/json

{
  "customer_id": {{customer_id}},
  "items": [{ "sku": "APRON-01", "qty": 2 }]
}

假设响应 body 携带了新的订单 ID,您可以通过普通的响应断言将其存入名为 order_id 的变量中。现在打开该请求的后置操作。在文档模式下,您可以在 Run 选项卡中找到它们;在调试模式下,它们位于 Request 选项卡中。将鼠标悬停在添加后置操作上,选择数据库操作,将其命名为 verify order row,然后选择您的连接。

Configure Operation 下,选择操作并输入 SQL:

SELECT id, status, total_cents
FROM orders
WHERE id = {{order_id}};

查询结果将以 object 数组的形式返回,每行对应一个 object。若要提取单个字段,请展开 Extract Results (Optional) 并添加一个 Extract Result To Variable 记录。将 Variable Name 设置为类似 db_order_status 的值,并设置用于从第一行提取该字段的 JSONPath Expression

$[0].status

点击 Send 并查看 Console,以查看原始结果和提取的值。现在 db_order_status 已保存了磁盘上的实际数据。添加一个断言,验证其是否等于 pending(或你的 API 应该设置的任何值),这样你的测试最终就能够验证数据持久化,而不仅仅是 HTTP 响应回显。如果 API 返回了 201 但实际写入了 status = 'draft',则可以在此步骤中捕获该问题。

步骤 4:提取数据库值并在下游使用

提取不仅用于断言。通常,数据库中会保存一些响应中从未返回的值,而你在下一个请求中需要用到它。

设想这样一个流程:创建订单时,服务端还会生成一个内部的 fulfillment_ref 并写入该行数据,但该值在 API 响应中被忽略了。你的下一个请求 GET /api/fulfillments/{ref} 需要用到它。请在后置操作中查询该值:

SELECT fulfillment_ref
FROM orders
WHERE id = {{order_id}};

使用 Variable Name fulfillment_refJSONPath Expression $[0].fulfillment_ref 提取它。由于 Apifox 会将该变量的作用域限制在环境中,因此你的下一个请求只需在其 path 参数或 body 中引用 {{fulfillment_ref}},即可获取由服务端生成的真实值。这与链式调用 HTTP 响应(在测试步骤之间传递数据以及 API 测试场景编排和数据传递中所涵盖的内容)模式相同,唯一的区别在于,这里的数据源是数据库表,而不是 JSON body。

MongoDB 和 Redis:NoSQL 变体

对于 NoSQL 存储,该处理器的运作方式相同,只是配置界面有所不同。这两者都是付费功能,请根据实际情况进行规划。Apifox 文档 提供了完整的字段参考(如果需要)。

MongoDB

添加一个数据库操作步骤,并选择 MongoDB 作为类型。这里你将获得一个包含 Find、Insert、Update、Delete 以及 Run Database CommandOperation Type 下拉列表,而不是原始的 SQL。对于任何 CRUD 操作,Collection Name 都是必填的。Query Condition 字段接收 JSON 数据:

{ "_id": "65486728456e79993a150f1c" }

Apifox 会自动将匹配 of ID 字符串转换为 ObjectId,因此你无需手动进行包装。当确实需要 BSON 类型时,它支持辅助函数 ISODate(...)ObjectId(...)NumberDecimal(...)NumberLong(...)MongoDB 手册中记录了这些函数与存储值之间的映射关系。连接既可以接收完整的连接字符串,也可以接收单独的 host 和凭据组件。

提示:MySQL 流程文档中记录了将 JSONPath 提取到变量中的操作,但 MongoDB 和 Redis 文档并没有说明相同的将结果提取到变量 (Extract Result To Variable)机制。因此,请依赖 Mongo 操作进行数据播种和确认状态,在控制台中验证之前,不要假设 SQL 风格的提取路径工作方式完全相同。

Redis

Redis 连接需要填写 HostPortPasswordDatabase Index。可视化操作使用一个支持 GET、SET 和 DELETE 的操作类型 (Operation Type)下拉菜单。若要读取缓存的会话,选择 GET 并将 Key 设置为类似 user:session:123 的值。对于下拉菜单未涵盖的其他操作,可以使用 Run Redis Command 标签页运行任意有效的命令:

KEYS user:*

这样,你就可以确认接口本应写入的缓存条目,或者在测试前清除缓存,以验证接口是否会重新填充它。

高级变体与限制

在构建大型套件之前,有几点需要了解:

  • 循环。 当你在 ForEach 步骤中迭代多行时,可以使用 {{$.StepID.element.field}} 引用当前循环项,其中 StepID 是该循环步骤的实际编号。这对于在每次迭代中断言单行非常方便。
  • 基于数据库值进行分支。 提取状态字段,然后根据该字段路由后续的测试场景。在接口测试场景中,将数据库读取与条件逻辑结合使用,可以让测试在数据行为 paid 时走一条路径,在为 pending 时走另一条路径。
  • 环境路由。 详见下文,简而言之:为每个环境定义一个连接,Apifox 会自动选择正确的连接。
  • 存储过程。 可视化界面不支持存储过程等复杂操作。请将步骤中的 SQL 保持为简单的语句。
  • Oracle 配置。 Oracle 需要先在你的本地机器上安装独立的 Oracle Client 才能进行连接。

按环境管理凭据

你绝不希望测试意外触及生产数据。Apifox 的解决方案是为每个环境配置一个数据库连接。你可以创建一个 staging 连接和一个 local 连接,每个连接都有自己的主机和密码。

然后,你只需使用右上角的下拉菜单切换环境。Apifox 会自动将测试场景中的每个查询路由到与当前所选环境匹配的连接。选择 staging,你的 SELECT 就会在 staging 环境中运行;切换到 local,完全相同的步骤就会在你笔记本电脑的本地数据库中运行,无需修改 SQL 或步骤。凭据会根据不同的环境自动区分,在运行过程中无需任何手动重新配置。

由于这些凭据保存在本地且不进行同步,这也避免了生产密码被泄露到共享的云端项目中。每位工程师只掌握自己的凭据。

使用 Apifox CLI 实现工作流自动化

一旦测试场景在 App 中运行通过,就可以在 CI 中以无头 (headless) 模式运行它,以便每次 Pull Request 都能重新验证数据库,而不仅仅是验证 HTTP 契约。安装 CLI 并进行身份验证:

npm install -g apifox-cli apifox login --with-token

然后根据其 ID,针对选定的环境运行您构建的具体测试场景:

apifox run --access-token $APIFOXACCESSTOKEN -t-e-r cli

这里 -t 是测试场景 ID,-e 是环境 ID,而 -r 是报告格式(clihtmljunit;若需要多个,可用逗号分隔,例如 -r html,cli)。需要注意的一点是:数据库连接凭据是保存在本地的,因此 runner 需要导入已导出的配置,才能在 CI 环境中连接到您的数据库。如果您使用数据集中的多行数据来驱动测试场景,Apifox CLI 的数据驱动测试可以向您展示每行数据是如何执行相同的数据库断言的;此外,使用 Apifox 的定时任务来调度 API 测试,可以让这些测试按设定的频率自动运行,从而使数据库断言失败能像普通测试失败一样被及时暴露出来。

常见问题

哪些数据库是免费的,哪些是收费的? MySQL、SQL Server(2014 及更高版本)、PostgreSQL 和 Oracle 包含在免费版中。ClickHouse、MongoDB 和 Redis 则需要付费版。MongoDB 和 Redis 的文档都指出其连接功能是付费特性,因此在规划 NoSQL 测试套件之前,请先查看价格页面。您可以先下载 Apifox 来试用免费的数据库。

我可以在后续的请求中使用数据库中的值吗? 可以。添加一个包含数据库操作的后置操作,运行 SELECT 语句,然后使用“提取结果到变量”功能,通过设置变量名和 JSONPath 表达式(例如 $[0].fulfillment_ref)从第一行数据中提取出所需的字段。之后便可以通过 {{variable_name}} 来引用它。在测试步骤之间传递数据中也介绍了针对 HTTP 响应的相同链式调用思路。

我的队友会自动获取我的数据库连接吗? 不会。连接凭据存储在每个客户端的本地,不会同步到云端,因此每位团队成员都需要自己配置连接。这是刻意设计的:它可以防止生产环境的密码泄露到共享项目中。

我的 MySQL 8 连接一直失败,为什么? MySQL 8 默认使用 caching_sha2_password 的 auth 插件,这可能会阻止连接。请使用 ALTER USER ... IDENTIFIED WITH mysql_native_password 将用户的认证方式切换为 mysql_native_password,然后重新连接。

我可以运行存储过程或复杂的数据库逻辑吗? 无法通过可视化界面直接运行。该界面支持标准的 SELECT、INSERT、UPDATE 和 DELETE 语句,但不支持存储过程等复杂操作。请在测试步骤中保持使用直接的执行语句。

总结

数据库查询使 API 测试从“响应看起来正确”提升为“数据确实正确”。在同一个测试场景中,您可以在前置操作中预置已知状态,在后置操作中验证持久化的数据行,并提取服务端生成的值以供下一个请求使用。为每个环境配置连接后,相同的测试步骤即可安全地在 staging 环境或本地运行,无需进行任何修改。

免费试用,无需信用卡:下载 Apifox,将 MySQL 连接指向你的开发数据库,并添加一个后置操作来读取下一个请求所创建的数据行。

开发必备:API 全流程管理神器 Apifox

介绍完上文的内容,我想额外介绍一个对开发者同样重要的效率工具 —— Apifox。作为一个集 API 文档、调试、设计、测试、Mock、自动化测试于一体的工具,Apifox 是目前提升研发效率的首选。

如果你正在开发项目,不妨试试其极其友好的界面设计,它完全兼容 Postman 和 Swagger 数据格式,导入数据非常方便,,即使是新手也能很快上手,点击这里即可注册使用

Apifox

值得一提的是,除了个人和常规团队使用,针对有高安全合规要求、或需要在内网环境协作的企业,Apifox 还提供了深度定制的私有化部署方案

获取专属报价与部署方案

icon 详细的私有化部署系统架构与安全白皮书
icon 针对您公司规模的专属报价单
icon 免费的 1v1 专属产品演示 (Demo) 机会
获取部署方案
* 提交后,我们的客户经理将在 1 个工作日内与您联系
林俊锋 企业微信
@Apifox 专属顾问
扫码备注: 私有化 + 公司名