接口没写完、前端只能干等,这事儿在并行开发的项目里几乎每周都会上演。我印象最深的一次是接一个第三方能力,对方给的测试环境一天能挂三四回,前端同学最后干脆在代码里硬编码一段 JSON 顶着,结果联调那天真接口返回的字段名跟硬编码的差了两个字,白白返工半天。后来我把团队里的做法统一了一下:所有还没就绪、不稳定、不归我们管的接口,一律用一个本地 API mock 服务顶着,而用得最顺手的工具就是 Mockoon。它不是那种要注册账号、把请求发到别人服务器上的在线 mock 平台,而是一个装在本机的桌面程序,点几下就能起一个真实的 HTTP 服务,前端、自动化测试、甚至 curl 都能直接打。这篇文章我想把 Mockoon 从"装完怎么用"讲到"怎么把它塞进团队流水线",包括模板语法、响应规则、代理模式、CLI 和容器化,还有我自己踩过的那些坑,适合正在做前后端分离开发的工程师、需要给测试造数据的同学,以及要给外部依赖做兜底方案的人。
1. Mockoon 值得替换掉我手上那堆手工 mock 脚本的三个理由
1.1 手工 mock 服务的隐性成本比想象中高
大部分人第一次做接口 mock,路径都差不多:新建一个 Node 工程,装个 express 或者直接用 json-server,写十几个路由返回固定 JSON,然后node server.js。跑通的那一刻确实很爽,但这个方案的成本是延后爆发的。首先是环境漂移,你改了/api/user/profile的返回结构,同事本地那份还是三天前的版本,前端调你这份能过、调他那份就报字段缺失,排查半小时最后发现是两套 mock 数据不一致。其次是启动负担,新人入职要 clone 仓库、装依赖、看 README 里那句"记得先启动 mock 服务",Node 版本不对还得先折腾 nvm。
还有两个更隐蔽的问题:一是没有可视化,想改一个返回字段得开编辑器找到对应行,改完重启进程;二是没有请求日志,前端说"我明明发了请求",你没法快速确认到底有没有打进来、带了什么参数。这些都是我真实经历过的摩擦,单看每一条都不致命,加起来就是每天的时间黑洞。
1.2 Mockoon 的产品形态决定了它的上手成本极低
Mockoon 是一个开源的桌面应用,Windows、macOS、Linux 都有安装包,下载双击就能用,不装运行时、不依赖 Node 环境、不需要注册任何账号。它在界面上暴露的概念非常少:环境(Environment)、路由(Route)、响应(Response),三层就到底了。你在界面上点加号建一条路由,选方法、写路径、贴一段 JSON 当返回体,点一下启动按钮,一个监听在本机端口的 HTTP 服务就起来了。
我认为它最被低估的一点是"配置即资产"。你搭的整个 mock 环境可以一键导出成一个 JSON 文件,丢进 Git 仓库,同事拉下来导入就是一模一样的环境,连延迟设置和响应规则都不会丢。这就把"每个人各自搭一套"变成了"团队共用一份契约",前面说的环境漂移问题从根上消失了。而且它完全跑在本地,请求不出机器,对于内部接口、涉及业务字段的返回结构,这种离线特性比在线 mock 平台省心得多。
1.3 它的能力边界:哪些场景别硬用
工具再好也有干不了的活,提前说清楚省得后面白折腾。Mockoon 本质上是一个"按配置返回响应"的 HTTP 服务,它最大的短板是没有真正的持久化状态。你可以用数据桶模拟一份列表数据,也可以根据请求参数挑不同的响应,但如果你需要一个真正的增删改查闭环——POST 进去一条、GET 列表能看到它、DELETE 之后再 GET 就没有了——Mockoon 原生做不到,它不提供可写的存储层。这类需求更合适的选择是自己写一个带内存存储的小服务,或者用带状态能力的服务虚拟化工具。
另外它专注在 HTTP/HTTPS 这一类接口上,如果你的系统里大量依赖 WebSocket 长连接或者 gRPC,Mockoon 帮不上太多忙。所以我的建议是把它定位成"HTTP 接口的仿真器",覆盖前后端并行开发、第三方依赖兜底、演示环境、自动化测试的数据前置这几类场景,这些占到日常工作的八成以上。
2. Mockoon 的运行模型:一个配置文件 + 一个本地 HTTP 服务
2.1 环境是最小的可交付单元
Mockoon 里所有东西都挂在"环境"这个对象下面。一个环境里包含了监听的端口、绑定的主机名、路径前缀、所有路由定义、响应头全局配置、数据桶、代理设置等等。启动一个环境,就等于启动了一个独立的 HTTP 服务实例。你可以同时开多个环境,比如一个模拟用户中心跑在 3001,一个模拟订单中心跑在 3002,前端在配置文件里把两个域名分别指过去就行。
这个设计对应到真实项目里非常自然:按后端微服务的边界来划分环境,一个服务一个环境,谁负责的接口谁维护那份 JSON。我在上一家公司就是这么干的,六个环境文件放在仓库的mocks/目录下,每个文件的主人写好之后在群里喊一声,前端自己去导入。相比一个巨型 mock 服务里塞几百条路由,这种方式的分工和冲突处理都清爽很多。
2.2 路由和响应是两层结构
理解这两层,后面所有高级用法都好说了。路由决定"什么样的请求会被这个条目接住",它由 HTTP 方法加路径组成,路径支持路径参数,比如orders/:id,也支持通配符。响应决定"接住之后返回什么",一个路由下面可以挂多个响应,每个响应有自己的状态码、响应头、响应体、延迟时间,以及一组匹配规则。
默认情况下一个路由的多个响应里有一个是"默认响应",当所有带规则的响应都没匹配上时用它兜底。这就给了我们一个很强的能力:同一个 URL,带不同查询参数返回不同结果,带错误 token 返回 401,请求体里字段不合法返回 422,全部在一条路由里搞定,不需要为了造几个异常场景去复制粘贴一堆路由。
2.3 端口、主机名与前缀三个设置项
端口不用多说,注意别撞上你本机已经在跑的服务,常见的 3000、8080 经常被占,我习惯从 3001 起往后排。主机名这个设置值得单独提一句:默认是本机回环地址,只有本机能访问;如果改成0.0.0.0,同一局域网里的手机、平板、同事的机器就能通过你的 IP 访问到。这个在移动端调试时特别有用,手机连同一个 Wi-Fi 就能直接请求你电脑上的 mock 接口,省掉一堆端口转发配置。
路径前缀(endpointPrefix)是个容易被忽略但很有用的设置。它会给这个环境里所有路由统一加一段前缀,比如填api,那你定义的路由orders实际对外就是/api/orders。这样做的好处是前端代码里的 baseURL 不用为了 mock 单独改,只要把域名换成 mock 服务的地址,路径结构跟真实后端保持一致,切回真接口时只改一个域名变量。
2.4 配置文件长什么样
导出的配置文件是一份结构清晰的 JSON,我截一段精简版给你看,理解了这个结构,你甚至可以直接手写配置文件批量生成路由:
{ "name": "订单中心 Mock", "port": 3001, "hostname": "0.0.0.0", "endpointPrefix": "api", "routes": [ { "type": "http", "method": "get", "endpoint": "orders/:id", "responses": [ { "statusCode": 200, "headers": [ { "key": "Content-Type", "value": "application/json" } ], "body": "{\"id\": \"{{urlParam 'id'}}\", \"status\": \"PAID\"}", "latency": 0 } ] } ] }要注意不同大版本之间字段名和层级会有调整,比如规则的字段结构在较新版本里做过重构,数据桶的表达方式也变过。所以我的建议是:配置文件以界面导出为准,别拿着老版本的示例去手改新版本的字段,导入失败一般就是这类原因。
3. 第一次跑起来:从空环境到前端能调通的第一条接口
3.1 新建环境时先把两个值定下来
打开 Mockoon 之后新建一个环境,界面上会有一堆设置项,但第一次只需要关注两个:端口和主机名。端口我建议直接选一个你项目里真实后端不用的号段,比如 3001 到 3009 之间,避免和开发服务器打架。主机名先用默认的回环地址,等你需要手机调试时再改成0.0.0.0。
还有一个小细节:环境名称一定要写成有辨识度的。我在一个项目里见过五个环境分别叫"New environment"、"New environment (1)"、"New environment (2)",光看名字根本不知道哪个是订单、哪个是支付。命名规范建议直接照抄后端服务名,比如order-service-mock、user-service-mock,导出文件名也保持一致,后期维护成本能降一大截。
3.2 加一条 GET 路由,把返回体写对
点添加路由,方法选 GET,路径写orders/:id,然后在响应的 body 区域贴上 JSON。这里有个新手必踩的坑:body 默认是纯文本编辑模式,你贴进去的是字符串内容,所以一定要确认响应头里有Content-Type: application/json,否则前端用 axios 拿到的是字符串而不是对象,res.data.list会是 undefined,然后前端同学跑来问你接口是不是坏了。Mockoon 在新建响应时通常会带一个默认的 JSON 头部,但你自己改过 body 类型之后要回头检查一遍。
路径参数冒号后面那一段名字,就是后面模板里引用它的 key。写orders/:id,模板里就用{{urlParam 'id'}}取;写orders/:orderId,模板里就是{{urlParam 'orderId'}}。这个名字前后必须对上,对不上不会报错,只会返回空字符串,属于很隐蔽的问题。
3.3 CORS 是前端联调第一大拦路虎
如果你的前端页面跑在http://localhost:5173,mock 服务在http://localhost:3001,这就构成跨域了。浏览器会先发一个 OPTIONS 预检请求,如果 mock 服务没正确回应,真正的请求根本发不出去,控制台报的是 CORS 错误,很容易被误判成"mock 服务没起来"。
Mockoon 的环境设置里有一个跨域相关的开关,打开之后它会自动处理预检请求并在响应里补上必需的头部。如果你的项目需要带 Cookie 或者自定义鉴权头,记得把允许的头部和凭证相关的设置一并配好,只开一个总开关有时候不够。我自己的经验是:先用浏览器直接访问接口地址验证服务本身通了,再从前端页面发请求,这样能把"服务没起"和"CORS 没配"两类问题彻底分开,省下大量瞎猜的时间。
3.4 用两种方式各验一遍
服务起来之后,先别急着开前端工程。第一步在浏览器地址栏直接敲http://localhost:3001/api/orders/10086,能看到 JSON 就说明路由和响应都没问题。第二步用命令行再打一次,能看到完整的状态码和响应头:
curl -i "http://localhost:3001/api/orders/10086"命令行这一步的价值在于你能看到响应头,Content-Type对不对、CORS 头部有没有加上、状态码是不是 200,一目了然。第三步再去前端页面发请求。按这个顺序走,出问题时你永远知道是哪一层挂了,而不是面对一个红色的报错一路往回猜。
3.5 铺接口的顺序:先骨架后细节
新接手一个模块要 mock 十几条接口,我的习惯是先花十分钟把路由清单列出来,全部建成"方法 + 路径 + 空对象返回",先把服务跑起来让前端不阻塞;然后再逐条把返回体填成符合约定的结构。理由很实际:前端最需要的是"接口存在且能调通",字段可以一点点补,但如果接口压根不存在,他们连页面骨架都搭不起来。
4. 让假数据不再是死数据:模板引擎的用法与边界
4.1 模板在 Mockoon 里处于什么位置
Mockoon 的响应体、响应头、部分配置项里都可以内嵌模板表达式,语法基于 Handlebars,用双大括号包起来。它的作用是在每次请求进来的时候动态算出一段内容填进去,而不是返回写死的字符串。这一点非常关键:意味着你不用为了模拟十条不同的数据去建十条路由,一条路由配一段带循环和随机值的模板就够了。
需要注意模板是"求值"而不是"执行代码",你不能在里面写任意脚本,只能调用它内置的那些 helper。这种限制是好事,配置能安全地共享给任何同事,不用担心有人塞进去一段读本地文件的逻辑。
4.2 读取请求:把参数原样带回来
最常用的四类取值 helper 是:
| 用途 | 写法示例 | 说明 |
|---|---|---|
| 路径参数 | {{urlParam 'id'}} | 对应orders/:id里的 id |
| 查询字符串 | {{queryParam 'page'}} | 取?page=2的值,取不到返回空 |
| 请求体字段 | {{body 'user.name'}} | 支持点号路径访问嵌套字段 |
| 请求头 | {{header 'X-Token'}} | 常用于把鉴权头回显出来做验证 |
| 整个请求体 | {{bodyRaw}} | 返回未解析的原始字符串 |
把这几个用好,很多场景就通了。比如前端要验证"详情页拿到的是不是我请求的那条数据",返回体里直接{{urlParam 'id'}}回显,一眼就能确认链路对不对。再比如做登录接口时,把请求头里的 token 值直接拼进返回体,前端就能验证自己的请求拦截器有没有正确挂上头部,这种"回显"技巧在排查前端网络层问题时特别好用。
4.3 生成数据:随机值与循环
Mockoon 内置了随机数据生成能力,较新的版本沿用了 Faker 这类数据生成库的语义,可以生成人名、邮箱、地址、公司名、UUID、日期等等。这里我要提醒一点:不同大版本使用的模块路径不一样,较早的版本里写{{faker 'name.firstName'}}这种旧式路径,较新版本改成了{{faker 'person.fullName'}}这样的新路径。写错了不会报错,只会把表达式原文吐出来,非常容易让人以为模板坏了。稳妥的做法是打开界面里的模板 helper 提示列表,从里面直接挑一个复制,别凭记忆手写。
结构化数据靠循环来造。比如要返回一页列表:
{ "total": 48, "list": [ {{#repeat 10}} { "id": {{index}}, "name": "{{faker 'person.fullName'}}", "createdAt": "{{date 'yyyy-MM-dd'}}" } {{/repeat}} ] }{{#repeat n}}之间的内容会被重复 n 次,{{index}}是当前迭代的序号。生成十条随机用户、二十条订单记录,都是几行代码的事。提醒一句:循环体内最后一个元素的逗号问题,Handlebars 的 repeat 不负责帮你处理 JSON 末尾逗号,如果结构设计不当会出现多余的逗号导致 JSON 解析失败,稳妥写法是让每次迭代都完整输出一个对象加逗号,并在最外层自己控制好边界,或者干脆用"每项独占一行、最后一项也带逗号、用宽松解析的前端"这种偷懒做法——我不推荐后者,因为它会在真接口上埋雷。
4.4 数据桶:一份数据给多条路由复用
数据桶是 Mockoon 里我最喜欢的功能之一。它允许你在环境级别定义一份数据,可以是一段静态 JSON,也可以是一段带模板的生成逻辑,然后在多条路由里通过{{data '桶名或ID'}}引用它。这样一个"用户列表"只在数据桶里定义一次,列表路由、详情路由、搜索路由都能从这里取,改了数据桶所有引用它的地方一起变,维护成本直线下降。
使用时有两点要注意。第一,数据桶的引用参数在部分版本里要求写 ID 而不是显示名称,导出文件里能查到具体值,写错了同样不报错只返回空。第二,也是前面提过的边界——数据桶是只读的。它不会因为你发了一个 POST 请求就自动往里追加数据,跨请求的数据变更它管不了。如果你的测试用例严格依赖"写进去再读出来",别在这个工具上耗时间,换方案更省事。
4.5 什么时候该关掉模板解析
模板偶尔会给你带来麻烦。最典型的情况是返回体里本身包含双大括号,比如要模拟一段前端模板代码、一段 Markdown 文档、或者是某个第三方接口返回的错误信息里正好带了花括号。这时候模板引擎会尝试解析它,解析失败就原样输出,解析成功反而把内容改掉了。Mockoon 的响应设置里提供了关闭模板解析的选项,遇到这类含有花括号的返回体,直接把这个响应关掉解析最省心,比想办法转义可靠得多。
5. 同一路径返回不同结果:响应规则、延迟与错误注入
5.1 一条路由多响应,比复制十条路由干净
真实项目里同一个接口在不同输入下表现完全不同:正常返回 200、token 过期返回 401、参数校验失败返回 422、服务异常返回 500。如果每条分支都建一条路由,你很快就会有一个几十条路由的混乱环境,改字段还得挨个改。Mockoon 的做法是在一条路由下挂多个响应,每个响应配一组规则,请求进来时从上往下匹配,第一个满足条件的响应被使用,都不满足则用默认响应。
这个模型我用了很久,它最大的价值是把"接口的完整行为"收敛在一个地方。前端想测异常分支,只要构造出触发条件就能拿到对应的错误响应,不需要等你手动去改返回体。这种能力让前端的错误处理代码终于有机会被真正测到,而不是上线之后靠用户反馈来发现问题。
5.2 规则的四个组成部分
一条规则由四块信息组成,理解它们就能配出绝大多数场景:
| 组成部分 | 含义 | 常见取值 |
|---|---|---|
| 目标位置 | 从请求的哪里取值 | 请求体、查询参数、请求头、路径、完整 URL |
| 定位符 | 具体取哪个字段 | 字段名、参数名、头部名 |
| 匹配方式 | 怎么比较 | 相等、正则匹配、为空、非空、包含于数组 |
| 期望值 | 用来比较的值 | 字符串或正则表达式 |
组合起来就非常灵活。比如"当查询参数role等于admin时返回带权限字段的响应",目标位置选查询参数,定位符写role,匹配方式选相等,期望值填admin。再比如"当请求头里的 trace 值符合某个正则时返回特定内容",匹配方式换成正则即可。多条规则之间还可以选择"全部满足"或"任一满足"的逻辑关系,前者用来做复合条件,后者用来做多值并列。
5.3 用延迟把加载态逼出来
前端很多 UI 问题只在慢网络下暴露:骨架屏没出、加载动画闪一下、重复点击导致重复提交。本地 mock 接口响应速度是毫秒级的,这些问题永远不会出现。Mockoon 的每个响应都能设置延迟,可以是固定值,也可以是一个随机范围,比如 300 到 1500 毫秒之间随机。
我自己的习惯是:主流程接口延迟统一设个三四百毫秒,让开发者能感知到加载态的存在;专门留一两个接口设成三到五秒的慢响应,用来验证超时提示、取消请求、按钮防重复点击这些逻辑。这些小设置花不了两分钟,但能让一类线上问题在开发阶段就被提前发现。注意随机延迟的写法在不同版本里略有差异,有的是填一个区间,有的是用模板生成随机数,以你所用版本的界面为准。
5.4 主动造错,让错误分支有数据可测
错误注入的价值经常被低估。前端的错误提示文案写得漂不漂亮、重试逻辑会不会死循环、后端的错误结构解析对不对,这些都依赖真实拿到过一个错误响应。构造方式很简单:新建一个响应,状态码填 500,返回体按你们后端的统一错误格式写,比如带一个错误码和一个可读信息,然后给它配一条几乎不可能满足的规则,或者干脆做成用特殊查询参数触发的开关。
我更推荐后者——用参数开关触发。比如所有请求带上?mock=error就返回 500,不带就是正常响应。这样测试想要异常场景时不用改配置,加个参数就行,正常开发和自动化用例都不会被影响。这个约定值得在团队里固定下来,写进 mock 环境的说明里。
5.5 配了规则却不生效,怎么查
这算是规则功能里最高频的困惑,我遇到过好几次,总结下来就三个原因。第一,规则的目标位置选错了。你以为参数在查询字符串里,其实前端是放在请求体 JSON 里发的,位置不对自然匹配不到。第二,响应顺序。多个响应是从上往下匹配的,如果你把默认响应放在了带规则的响应前面,或者某个宽泛的规则排在了前面,它就会抢先命中。第三,值的类型和大小写。查询参数永远是字符串,你拿它跟数字比较就可能失败;正则没加忽略大小写标志,Admin就匹配不上admin。
排查手段也很直接:打开 Mockoon 的请求日志,看实际到达服务的那条请求里,参数是什么形态。日志里能看到请求方法、路径、查询参数、请求头,一眼就能判断是你的规则写错了还是前端压根没把参数发出来。我强烈建议把请求日志一直开着,它的信息量比你想象的大。
6. 代理模式:真接口和假接口可以同时存在
6.1 代理响应解决的是"灰度替换"问题
代理模式是 Mockoon 里一个很实用的进阶能力。它的作用是:当某个路由被请求时,Mockoon 不返回本地定义的假数据,而是把请求转发到真实的服务器,把真实响应原样返回给调用方,同时你还能在中间做点手脚(比如改写路径、注入头部)。这个能力在几种场景下特别有用:
- 后端已经有部分接口上线了,你想让前端逐步切到真接口,没上线的继续用 mock;
- 你想观察真实接口返回的数据长什么样,用来把 mock 数据对齐到真实结构;
- 第三方接口只在特定条件下不可用,你想做一层兜底。
6.2 配置代理目标和路径
配置方式是在响应的类型里选择代理,然后填上目标地址。这里的关键是路径重写:你本地的路由路径和真实后端的路径往往不一致,需要明确告诉它转发过去时用什么路径。很多人在这一步卡住,表现是"转发过去了但返回 404",多半就是路径拼接出了问题,多一个斜杠或者少一段前缀都会导致 404。
我的经验是先把目标地址配到"能返回任何东西"的程度,比如直接指向对方的健康检查接口,确认连通性没问题,再改成真实路径并调路径重写。一次只改一个变量,比一次性配好所有东西然后对着 404 发愁高效得多。
6.3 环境级兜底:没定义的路由自动转发
除了单个路由的代理,环境级别通常还能设置"未匹配路由"的行为,其中一种就是转发到指定地址。开启之后,你在这个环境里定义的路由用 mock 数据,没定义的路由自动打到真实后端,两者混在同一个 baseURL 下,前端完全感知不到区别。这个模式在做渐进式迁移时非常舒服:随着后端接口一个个上线,你只需要把对应的 mock 路由删掉,删到最后一个都不剩,前端代码一行都不用改。
用这个模式时有两点要留意。一是转发会真实打到后端,如果你的 mock 环境里定义了带副作用的写操作又被误转发,可能真的产生数据,测试环境尤其要小心。二是延迟和响应头,本地 mock 的延迟设置不会作用于转发的响应,转发的耗时完全取决于后端,别拿"我设了 500 毫秒延迟"去解释为什么慢。
6.4 HTTPS 目标与自签名证书
转发到 HTTPS 的地址时,如果对方用的是自签名证书,本地转发通常会因为证书校验失败而报错。Mockoon 本身也支持让 mock 服务以 HTTPS 方式对外提供,它内置了生成证书的能力。以 HTTPS 提供服务之后,浏览器和命令行访问时会因为证书不受信任而给出警告,这在本地测试里属于预期行为,需要你在测试客户端里做相应配置,比如让 HTTP 客户端跳过证书校验——注意这只在本地联调环境使用,绝不能带到生产代码里。
7. 从桌面到流水线:CLI、Docker 与配置文件协作
7.1 配置文件怎么进版本库
这是把 Mockoon 从"个人工具"升级成"团队基础设施"的关键一步。做法很简单:每个环境导出一个 JSON 文件,放在仓库里一个固定目录下,比如mocks/,文件名跟服务名对齐。然后写一段简短的 README 说明怎么导入、各个文件对应哪个后端服务、端口怎么分配。别小看这段说明,它能省掉新人至少半天的摸索。
我还建议给配置文件加一条约定:只允许通过界面修改后导出,不要手工编辑 JSON。手工编辑容易改坏结构,尤其是规则和数据桶这种嵌套较深的部分。如果确实要批量改(比如统一改一批端口),写个脚本处理,处理完在界面上导入验证一次再提交。
7.2 用 CLI 在无界面环境启动
桌面应用没法跑在服务器和持续集成环境里,所以官方提供了命令行版本,可以从配置文件直接拉起 mock 服务。基本用法是指定配置文件路径、端口和主机名:
npx @mockoon/cli start \ --data ./mocks/order-service.json \ --port 3001 \ --hostname 0.0.0.0常用的还有打开请求日志的选项,方便在流水线里排查问题。需要提醒的是命令行版本在参数命名上跟桌面版不完全一致,而且不同大版本之间也调整过,我建议第一次用的时候直接跑一下帮助命令,看当前版本的参数列表,别照抄网上可能过时的示例。
7.3 容器化时最容易踩的网络坑
用容器跑的时候,新手最常遇到的问题是"容器里起了,但宿主机访问不到"。原因基本都在主机名和端口映射上:容器内如果绑定的是回环地址,那只有容器内部能访问,必须绑到0.0.0.0;同时启动容器时要把内部端口映射到宿主机。如果其他容器也要访问这个 mock 服务,注意它们之间要用容器网络里的服务名互相寻址,而不是localhost——localhost在容器里指的是它自己。
调试这类问题的思路很简单:先在容器内部用命令行打一次接口,确认服务本身起来了;再从宿主机打一次;最后从调用方打一次。三层分开验证,比对着一个连接超时发呆快得多。
7.4 在持续集成里用它兜住外部依赖
把 mock 服务接进持续集成流程是我觉得收益最高的一步。典型场景是端到端测试依赖一个第三方服务,而那个服务在流水线里要么访问不到,要么不稳定。做法是在测试开始前用 CLI 拉起 mock 服务,跑完测试再关掉。
这里有个细节值得注意:拉起的进程要能在后台常驻,测试结束后要确保被回收,否则流水线会挂住不结束,看起来像卡死其实是某个后台进程没退出。另外,如果测试代码里需要动态改返回内容,纯配置文件的方式就不太够了,一般会考虑用接口的方式在测试中切换,或者干脆针对每个用例单独准备一份配置文件。
7.5 多环境的配置怎么组织
一个稍微正规点的项目通常会有几套 mock:日常开发用的、演示用的、自动化测试用的。它们大部分路由是重合的,差异在端口、部分数据和延迟上。我的做法是维护一份"主"配置文件作为基线,其余套件用脚本在它基础上改几个字段生成,而不是维护三份几乎一样的东西各自演进。手工维护多份配置的结局一定是某一份慢慢腐化,最后没人敢用。
8. 我踩过的坑:从端口占用到模板转义
8.1 端口占用导致的"服务起不来"
启动环境时报端口已经被占用,这是最常见的一个错误。Linux 和 macOS 上可以用命令查一下是谁占了端口:
lsof -i :3001Windows 上用netstat -ano | findstr :3001,找到进程号再决定是停掉它还是换端口。更隐蔽的一种情况是:端口没被占用,服务也提示启动成功,但请求就是打不通。这种情况优先怀疑主机名设置,如果绑的是回环地址而你从别的机器访问,自然是打不通的。
8.2 模板写错不报错,只把原文吐出来
这个坑我踩过好几次。模板表达式写错了,Mockoon 不会给你一个红色的错误提示,它会直接把那段大括号原文当成字符串返回。你在前端看到{{urlParam 'id'}}这样的字面量,第一反应往往是"服务坏了",其实是表达式没被识别。常见的出错原因是引号用了中文引号、括号不配对、helper 名字写错。
我的排查习惯是:遇到返回体里出现大括号原文,先把这段表达式单独提出来放进一个最简单的响应里测试,确认它能被解析,再放回复杂结构里。这样能把"表达式本身有问题"和"上下文影响了它"两种可能分开。
8.3 大返回体用文件管理更省事
当返回体膨胀到几百行 JSON 时,在界面的文本框里改就非常痛苦了——没有语法高亮,没有折叠,滚动起来还卡。Mockoon 支持把响应体指向一个本地文件,这样你可以用熟悉的编辑器维护那份 JSON,格式化、查错、版本对比都方便。
但用文件方式有个协作问题:文件是本地路径,你把配置导出给同事,他机器上没有这个文件,接口就跑不通了。所以如果团队要共享带文件引用的配置,要么约定好统一的相对路径结构并把这些文件一起提交到仓库,要么干脆把内容贴回响应体里。我在两个项目里分别用过这两种方式,人少的时候贴回去更省事,人多或者文件大的时候走文件引用更舒服。
8.4 多人同时改一份配置的冲突处理
配置文件是 JSON,多人协作时冲突几乎一定会发生。好在 JSON 的结构比较规整,按路由分块的话合并难度不大,但如果两个人同时改同一个路由的响应体,就得人工确认了。降低冲突的办法有几个:按后端服务拆分文件,别所有人都改同一个;改动前先拉最新版本导入界面;提交的时候顺手在提交信息里写清楚改了哪些路由。
最后再说一个我个人最常用的小技巧:在响应体的注释字段里给自己留信息。比如在返回 JSON 里加一个不参与业务逻辑的_mockNote字段,写上"这条规则用于模拟会员过期"、"这里的延迟是为了测试超时提示"。三个月后你再看这份配置,能立刻想起来当初为什么这么写。因为假数据迟早要对齐真实接口,而未对齐的原因往往比数据本身更容易忘。