执行自动化 ·(六)
一、系统一旦有外部依赖,测试会撞上什么
一个出海广告投放系统,运行时要调一堆不归你控制的东西:Google/Meta/AppsFlyer 的查点击与转化回传、支付、短信、风控,以及公司内别的团队的订单、账户、预算服务。于是测试撞上六类问题:
Mock 就是用一个"可控的假依赖"换掉"不可控的真依赖"。
二、Mock 的八个真实痛点
光知道"起个假服务"不够,真正磨人的是下面八条。
- HTTPS 拦不下来:不是工具不支持 HTTPS,而是证书信任链卡人——自签证书客户端默认不信(PKIX path building failed)、mTLS 要客户端证书、App 证书固定(Pinning)+ Android 7+ 不信用户证书连抓包都抓不到、QUIC/HTTP3 绕代理。
- Mock 被动不进化(最危险):后端把 status 改成 state、金额单位从元改分,你的假服务还按旧规则返回,测试一片绿,切真环境就崩。
- 搭起来慢、维护更慢:一条条手写匹配规则和返回体,接口一多就是体力活。
- 有状态、有顺序的场景难配:"前两次 500 第三次成功"(验重试)、"回调发两次账只记一笔"(验幂等)。
- 鉴权、签名、时间戳挡在前面。
- 数据太干净:全是 happy path,真实世界全是缺字段、null、超长串、非法枚举。
- 非 HTTP 协议管不了:gRPC、Kafka、Redis。
- 把流量切到假服务本身麻烦:地址写死、要改 hosts/配置、还可能忘记切回。
三、传统 Mock 全貌:按你测的产品选工具
mock 工具本质按"在链路哪一层动手"区分:服务边界起假服务(本文主线,WireMock 是事实标准)、进程内打桩(单测)、浏览器拦截(前端联调):
几个不分产品形态、谁都可能用到的通用工具层:
- 进程内打桩(写后端单测、不起服务):Java Mockito 5(已原生支持 static/final)、字节 Mockey;Python responses/respx;JS Jest mock。阿里 TestableMock 已转维护期。有代码权限时它和 WireMock 配合:单测打桩覆盖分支,链路用 WireMock 验真实协作。
- 抓包 / 代理:Charles、Fiddler 适合手工排查;mitmproxy 能用 Python 脚本篡改流量、可进 CI。
- 接口管理平台:Apifox、Eolink、ApiPost(接口文档即 mock、原生 HTTPS);⚠️ 早年的 RAP/RAP2、YApi 已停更多年(YApi 还有历史漏洞),存量尽快迁走,新项目不要选。
- 流量录制回放:GoReplay、AREX、jvm-sandbox-repeater(后者社区版久未大更新,选型先看维护活跃度)。
- 消费者驱动契约:Pact + Pact Broker,多团队微服务要"改了会不会搞挂调用方"的发布门禁时才上,不替代链路测试。
- mock 大模型接口:LLM 的 OpenAI 风格接口本质也是 HTTPS,WireMock 照样能 stub 它的 /v1/chat/completions(文末专门展开)。
整体看:Web/H5/桌面最省心,微服务切流量最优雅,小程序卡域名白名单,App(尤其安卓)证书坎最高。 不分产品形态,WireMock 几乎都能覆盖。只有三种情况再换手段:依赖不是 HTTP(testcontainers)、纯前端独立联调(MSW/Apifox)、多团队微服务要发布门禁(Pact)。
四、从 0 到进 CI:一条 Mock 落地主线(手工做法)
落地工具选用WireMock——一个独立的假 HTTP 服务器,贯穿示例用一个出海广告投放系统:被测系统会主动调投放服务的 GET /api/campaign/{id}(拉广告计划),还会被媒体 POST /api/callback/conversion(转化回传)主动回调。
mock 从头到尾就这一件事:让你的程序把原本发往真实依赖(Google/Meta、支付、别的团队的服务)的请求改发到 WireMock,由它按预设规则返回正常、边界、故障、超时等各种响应——用来模拟那些不归你掌控、测试时却要召之即来挥之即去的下游。 WireMock 是个独立的假 HTTP 服务器,谁发 HTTP 请求来它都接(官方适配清单里 Android、Java/Spring、Python、Node、.NET、Go、Kubernetes、Testcontainers 全都有),不挑调用方,规则只按"方法+路径+报文"匹配。要不要用 WireMock、在哪一层用它?标准只有两条,都与产品形态无关:
- 依赖走不走 HTTP:走 HTTP,才用得上 WireMock 这类独立假服务器(单元测试里也可用 Mockito/Mockey、MSW/Nock 这类进程内拦截);不走 HTTP(数据库、Kafka、Redis),用 Testcontainers 起真实依赖,别硬 mock。
- 在哪一层测:单元测试进程内打桩、不起 WireMock;集成测试起 WireMock(主力);少量端到端打真实下游只跑 happy path——接 CI 那步会把这三层落成流水线的两个阶段。
这条主线固定是下面 10 步,任何接口的 mock 都绕不开:
配通环境 ①起 WireMock → ②切流量 → ③过 HTTPS(按需)
准备资产 ④取契约 → ⑤写第一条规则 → ⑥造三层数据
执行 ⑦造故障验重试 → ⑧跑用例·接 CI
反方向 ⑨第三方主动回调你
长期兜底 ⑩防漂移(契约锁 + 录制对拍,持续回头做)
4.1 第①步:先摆好拓扑,把 WireMock 跑起来
手机 App 跑在真机/模拟器,WireMock 跑在你 PC 上,两者连同一个 WiFi:
安卓 App ──HTTPS──▶ PC 上的 WireMock (192.168.x.x:8443)
└─ 按规则返回假的广告计划 / 媒体响应
需要 Java 11+(WireMock 3.x 的最低要求;只有老的 2.x 还支持 Java 8),下载 wiremock-standalone-3.x.jar(一个 fat jar,零依赖),同时开 HTTP 和 HTTPS:
java -jar wiremock-standalone-3.x.jar --port 8080 --https-port 8443
一个进程同时服务两个端口、同一批规则通用。它是标准 HTTP(S) 服务器,App、网页、微服务来请求都一样接,不挑调用方。假设 PC 内网 IP 是 192.168.1.10,先用手机浏览器访问 http://192.168.1.10:8080/__admin,能打开说明网络通了(打不开就查 PC 防火墙、手机和 PC 是否同网段)。规则文件放当前目录的 mappings/,改完自动热加载。
4.2 第②步:让请求发到 WireMock——App 三种切法 + 后端环境变量
WireMock 起来了,但 App 默认还把请求发到线上域名,得让它改道。这一步只解决"怎么改道",规则怎么写放下一步。App 按推荐度三选一:
- 首选:要一个 baseURL 可切换的测试包,直接把接口域名填成 https://192.168.1.10:8443。这是可测性需求,排期时就跟开发提,代理、hosts、证书的折腾能省一大半。
- 次选:手机 WiFi 挂代理(Charles/mitmproxy,再由它转投 WireMock),适合临时排查。
- root 设备改 hosts:安卓 /system/etc/hosts 加一行 192.168.1.10 api.你的下游.com(PC 端是 C:\Windows\System32\drivers\etc\hosts),让域名解析到 WireMock。
不想起服务、只想让 App 页面快速有数据?还有一条端内路子:测试包里加 OkHttp Interceptor,命中配置直接回包、不命中放行,请求不出端。代价是绕过了真实网络、验不了容错——本文主线用 WireMock,拦截器只在纯页面联调时备选。
同一回事,后端服务怎么切? 上面三法解决的是"手机里的 App 怎么改道";换成跑在服务器上的后端,它没有可点的 baseURL 设置页、也没法挂手机代理,切法是下游地址读环境变量/配置文件——和 App 法①本质一样,都是让地址可配置,只是配置的地方不同。就配两处:
# ① 被测服务侧 config.py:默认值给真实地址,不被覆盖就永远走真的,天然防"忘切回生产"
AD_API_BASE = os.getenv("AD_API_BASE", "https://api.partner.com")
# ② 起被测服务时覆盖成 WireMock,就这一行
# 本地手工联调:export AD_API_BASE=http://localhost:8080 后再启动服务
# CI / docker-compose:
environment: [AD_API_BASE=http://wiremock:8080]
手工联调和后面 CI 自动化注入的是同一个变量,只是注入方式不同。地址外置本来就是正经后端的配置规范(生产切预发也靠它),不是为测试做的改造;开发连这行都不肯加,才退回到代理/hosts-DNS/网关/注册中心那类网络层劫持(零改代码,代价是要过下面的证书关)。
4.3 第③步:过 HTTPS 这一关(按需,App 最疼的一道坎)
真实接口都是 HTTPS。WireMock 本身完全支持 HTTPS,难点从来不是工具,而是让 App 信任那张证书——命令行加个 -k 就能跳过校验,App 可不行。按你的条件选一档:
档① 测试包信任测试 CA(最规范,推荐)。 让 WireMock 用内部测试 CA 签发的证书启动:
java -jar wiremock-standalone-3.x.jar --https-port 8443 \
--https-keystore /certs/test-downstream.p12 \
--keystore-type PKCS12 --keystore-password 你的密码
安卓测试包配 networkSecurityConfig,只在 debug 构建信任这张 CA(res/xml/network_security_config.xml):
<network-security-config>
<debug-overrides>
<trust-anchors>
<certificates src="system" />
<certificates src="@raw/test_ca" />
</trust-anchors>
</debug-overrides>
</network-security-config>
档② DEBUG 包代码里临时信任所有证书(最快,风险也最高)。 拿不到规范测试包时用,核心示意:
// 仅测试包生效:信任任意证书 + 跳过主机名校验
private static final X509TrustManager TRUST_ALL = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] c, String a) {}
public void checkServerTrusted(X509Certificate[] c, String a) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
};
static OkHttpClient.Builder bypassForMock(OkHttpClient.Builder b) throws Exception {
if (!BuildConfig.ENABLE_DEBUG_MOCK) return b; // 🔒安全闸:非 DEBUG 包直接返回,绝不装"信任所有证书"
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[]{TRUST_ALL}, new SecureRandom());
b.sslSocketFactory(sc.getSocketFactory(), TRUST_ALL)
.hostnameVerifier((host, sess) -> true);
return b;
}
🔴 必须用编译期 DEBUG 开关锁死在测试包,误带进线上等于关掉 HTTPS 全部保护。没源码、只能对现成包动手时才用 Frida / Xposed+JustTrustMe,且仅限自有 App、受控设备。
几个 App 特有的坑:
- 证书固定(Pinning):App 内置了服务器证书指纹,连测试 CA 也会被拒,测试包必须关掉 Pinning;
- QUIC/HTTP3 走 UDP 443 会绕开 TCP 代理,测试网络禁掉 UDP 443 逼它回落 TCP;
- iOS 不用写代码:装描述文件后还要去"设置→通用→关于本机→证书信任设置"手动开启,且受 ATS 限制默认禁明文。
档③ 下游是双向认证 mTLS——让 WireMock 反过来校验客户端证书。 支付、金融、内部系统常见:不止 App 要信服务器,服务器也要验 App 的客户端证书。让 WireMock 扮演这个下游时,挂上信任库、开启客户端证书校验:
java -jar wiremock-standalone-3.x.jar --https-port 8443 \
--https-keystore /certs/test-downstream.p12 --keystore-type PKCS12 \
--https-require-client-cert \
--https-truststore /certs/allowed-clients.p12 --truststore-type PKCS12
allowed-clients.p12 里放被测 App 的客户端证书;拿不出合法客户端证书的请求会在 TLS 握手阶段直接被拒——这本身也是一条要测的安全用例。
档④ 下游地址写死成 https、又装不了任何信任配置——用 Nginx 做 TLS 卸载。 老 App 既不能换包、也关不了证书校验,但下游域名能通过 hosts 指过来。让 Nginx 在 443 用合法 https 接住 App(证书由 Nginx 出、配进 App 信任库),解密后明文转给 WireMock 的 8080,把证书这道坎从 mock 工具挪给 Nginx——注意不是免证书,证书仍要让 App 信任:
server {
listen 443 ssl;
server_name api.partner.com; # App 要访问的下游域名
ssl_certificate /certs/partner.crt; # 配进 App 信任库
ssl_certificate_key /certs/partner.key;
# 下游若本就是 mTLS,可在此加 ssl_verify_client on; 由 Nginx 验客户端证书
location / {
proxy_pass http://127.0.0.1:8080; # 卸载 TLS 后明文转给 WireMock
proxy_set_header Host $host;
}
}
hosts 把 api.partner.com 指到这台 Nginx 即可。四档参数细节可对照 WireMock 官方 HTTPS 文档。
配通三步(起服务、切流量、过证书)做完,链路就通了。先用一个最简单的假响应验证改道成功——具体规则长什么样,正是下一步要写的。
4.4 第④步:取契约——动手写规则前,先搞清接口长什么样
很多人一上来就闷头写假 JSON,写完才发现字段是脑补的、金额单位搞反了,这正是痛点 3"字段靠脑补"。写规则前先拿到接口的真相(行话叫"契约"),来源按可靠度排:
- 有代码权限:DTO / VO、controller 的参数定义是最准的来源,字段名、类型、是否必填、校验注解都在上面;
- 有接口文档:OpenAPI/Swagger、Apifox 里的定义;
- 什么都没有:抓包(Charles/mitmproxy 导出 HAR)看真实请求响应,再找接口负责人口头确认。
抓包的 HAR 里混着埋点、心跳、鉴权刷新、静态资源,先把这些噪音剔掉,只留业务接口。对目标接口,手工也至少要在纸上/表格里列清这五项,一项都不能靠猜:
第⑤项最容易埋雷:枚举值域、金额单位(元/分)、时间字段的时区和窗口,必须找人闭环,宁可多问一句也别编。这张表就是后面写规则、造数据、做契约锁的共同依据——手工做法是自己填,下一章会看到 AI 能把 HAR/代码一键清洗成这张表。
4.5 第⑤步:写第一条规则(mapping)
链路通了、契约会了,现在写第一条真正的规则,验证端到端闭环。在 mappings/campaign.json 放:
{
"request": { "method": "GET", "urlPathPattern": "/api/campaign/[0-9]+" },
"response": {
"status": 200,
"headers": { "Content-Type": "application/json" },
"jsonBody": { "campaign_id": 1001, "name": "测试广告计划", "budget": 5000, "status": "ACTIVE" }
}
}
打开 App 的计划详情页(或用 curl/Postman 打被测系统),看到的正是这条假数据——第一个闭环通了。 规则里每个字段都对得上上一步那张契约表:budget 是整数分、status 取确认过的枚举,没有一个字段是拍脑袋的。
规则有两种配法,按用途选:
- 放 mappings/ 目录:进 Git、可评审、改完热加载,适合稳定的、要长期保留的规则;
- 运行时 Admin API 动态建:在用例里临时灌、用完即弃,适合每个用例各自不同的故障/数据:
curl -X POST http://192.168.1.10:8080/__admin/mappings \
-H 'Content-Type: application/json' -d @campaign.json
多条件的规则还能按 header、query、body 匹配,也可以给不同入参返回不同结果,这些按需查 WireMock stubbing 文档。
4.6 第⑥步:一次造三层数据——正常 / 边界 / 脏
只造一条 happy path 的假数据,等于只验证了"系统在一切顺利时不崩"。真实缺陷和资损几乎都藏在边界和脏数据里(痛点 6)。手工做法:围绕上一步的契约,把同一接口的数据按等价类分成三组,逐条造、逐条让被测系统过一遍:
C 层是重点中的重点:一条脏数据被当成合法数据收下,就是一个真 Bug(浮点金额、非法枚举、私加字段是最高发的三类,布尔是 int 子类、金额单位这类隐蔽项要专门造)。
手工造几条可以,但成批造很慢、还容易造得雷同。两个落地办法:
- 数据少:直接写在 mapping 的 jsonBody,或一个场景一个 mapping 文件;
- 数据成批:放 __files/ 目录存 JSON、mapping 里用 bodyFileName 引用;或写个脚本遍历数据文件,每条走 Admin API 动态灌。
这一步是手工和 AI 差距最大的环节:人编 5 条带业务关联的数据就累,AI 配 Faker 一次能给几百条还自带跨字段关联——下一章给现成提示词。但手工也必须先理解这三层的判法,否则 AI 造出来你也判断不了对错。
4.7 第⑦步:造故障和异常,验证重试与容错
光有正常/边界数据还不够,WireMock 最值钱的是不写业务代码就能模拟下游抽风,全在 response 里配:限流/服务错误 "status": 429 或 500;超时 "fixedDelayMilliseconds": 5000;断连/畸形响应 "fault": "CONNECTION_RESET_BY_PEER" / "MALFORMED_RESPONSE_CHUNK"。
重点看有状态的"前两次失败、第三次成功"——用来验证被测系统的重试逻辑,用 Scenarios(状态机)。把三条规则放进 mappings/ 下同一个文件:
{
"mappings": [
{ "scenarioName": "retry-then-success", "requiredScenarioState": "Started",
"newScenarioState": "r1",
"request": { "method": "GET", "urlPath": "/api/campaign/1001" },
"response": { "status": 500 } },
{ "scenarioName": "retry-then-success", "requiredScenarioState": "r1",
"newScenarioState": "r2",
"request": { "method": "GET", "urlPath": "/api/campaign/1001" },
"response": { "status": 500 } },
{ "scenarioName": "retry-then-success", "requiredScenarioState": "r2",
"request": { "method": "GET", "urlPath": "/api/campaign/1001" },
"response": { "status": 200,
"jsonBody": { "campaign_id": 1001, "name": "测试广告计划", "status": "ACTIVE" } } }
]
}
一组有状态规则放进 mappings/ 下同一个文件时,外层必须包一层 { "mappings": [ ... ] },不能直接丢一个裸数组(裸数组只在批量导入接口 POST /__admin/mappings/import 里才合法;文件里这么写不会被加载)。注意:凡是从 mappings/ 文件加载的规则都不适合在脚本里动态增删(文件规则归文件、热加载即可);要在用例里动态建、用完即弃,就走 Admin API——单条 POST /__admin/mappings,或一次性 POST /__admin/mappings/import 传 { "mappings": [ ... ] }。
怎么证明系统真的重试了?问 WireMock 要"被调次数":
curl -X POST http://192.168.1.10:8080/__admin/requests/count \
-H 'Content-Type: application/json' \
-d '{"method":"GET","urlPath":"/api/campaign/1001"}'
返回 {"count":3} 就是重试了 3 次的铁证;再配一个"恒 500",验证重试到上限后系统给出失败提示、次数停在上限。重试、熔断是被测系统自己的行为,WireMock 只按剧本返回,你只负责数次数,别在 mock 里替它实现重试。
4.8 第⑧步:跑用例、接进自动化和 CI
这一步把它沉淀成自动化回归并进 CI。技术栈用 Python + pytest + requests + docker compose,思路对任何语言都通用。
这一步以后端服务形态演示。 理由很实际:CI 是无人值守、随时要从干净环境从零拉起的,后端一条 docker compose up 就能把 WireMock 和被测服务一起起好、下游地址用环境变量注入、同一份代码两个阶段各部署一次——最轻、人人可复现;App 进 CI 还得准备模拟器/真机、装测试包、跑 Appium,重且不稳,不适合当最小示范。但 WireMock 侧的用法和被测形态无关:被测的是 App 时,把下面"pytest 直调被测服务"换成 Appium/Espresso 驱动那个指向 WireMock 的测试包即可,规则、Admin API 控制通道、数被调次数一个字都不用改。
下面按 ① 搭工程 → ② 放被测服务 → ③ 写夹具 → ④ 写用例 → ⑤ 写 compose 切流量 → ⑥ 本地两阶段跑 → ⑦ 挂 CI 的顺序走,每一步都有完整文件,照着建目录、贴代码就能跑通。
① 搭出工程目录。 最小可跑工程长这样,先把空目录和文件建出来:
mock-demo/
├── docker-compose.yml # 编排 WireMock + 被测服务
├── svc/ # 被测服务示例(你真实项目里换成自己的服务)
│ ├── app.py # 读 AD_API_BASE 转发下游、带重试
│ └── Dockerfile
├── wiremock/mappings/ # 稳定规则可挂卷进 Git
└── tests/
├── conftest.py # 连 WireMock/被测系统的公共夹具(两条通道 + 复位)
├── test_normal.py # 正常用例(无 marker,阶段①跑)
├── test_fault.py # 故障用例(打 mock 标)
└── test_smoke_real.py # 真下游冒烟(打 real 标 + 默认 skip)
② 放进被测服务。 真实项目里这就是你要测的后端,这里用标准库写个零依赖最小替身,关键只看它两点:从环境变量读下游地址(第②步主线说的"地址外置")、下游 5xx 最多重试 3 次(正好被后面的故障用例验证)。新建 svc/app.py:
# svc/app.py —— 一个会转发下游、且带重试的最小被测服务
import json, os, time, urllib.request, urllib.error
from http.server import BaseHTTPRequestHandler, HTTPServer
AD_API_BASE = os.getenv("AD_API_BASE", "https://api.partner.com") # 不被覆盖就走真的
MAX_RETRY = 3
def call_downstream(campaign_id):
url = f"{AD_API_BASE}/api/campaign/{campaign_id}"
for _ in range(MAX_RETRY):
try:
with urllib.request.urlopen(url, timeout=5) as r:
return r.status, r.read().decode()
except urllib.error.HTTPError as e: # 下游返回 500 会进这里
if 500 <= e.code < 600:
time.sleep(0.1) # 真实项目是退避策略,这里加速测试
continue
return e.code, e.read().decode()
except Exception:
time.sleep(0.1)
return 503, json.dumps({"error": "downstream unavailable after retries"})
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path.startswith("/campaigns/"):
cid = self.path.rsplit("/", 1)[-1]
status, body = call_downstream(cid)
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.end_headers
本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。
Implementation automation (vi)
I. What happens when the system is externally dependent?
An out-of-sea advertising system that runs with a bunch of things that are not under your control: Google/Meta/AppsFlyer's hits and conversion returns, payments, text messages, wind control, and orders, accounts, budget services from other teams in the company. So the test hit six types of problems:
Mock is to replace "uncontrollable real dependence" with "controllable false dependence".
Two, eight of Mark's real pains.
It's not enough to know that a fake service is going on.
- HTTPS cannot stop: not the tool does not support HTTPS, but the certificate trust card person - defaulted by the client of the visa book (PKIX path building bailed), mTLS to obtain client certificate, App Certificate Fixed (Pinning) + Android 7+ unconvinced user certificate cannot be captured, QUIC/HTTP3 bypass agent.
-Mock Passive Non- Evolution (most dangerous): The back end changes the status to state, the amount is split from dollar, your fake services return to the old rules, test green and the real environment collapses.
- Slow-up and slower maintenance: a handwritten matching rule and a return, with more interfaces than manual work.
- A state-of-the-art, sequenced scene is difficult to match: "The first two 500 and third success" (retry), "The return of the two accounts is only a one-sum payment" (Assays, etc.).
- Rights of attorney, signature, time stamp.
- The data are too clean: it's all happy path, and the real world is all missing field, Null, super long, illegal enumerators.
- Non-HTTP protocols do not control: gRPC, Kafka, Redis.
- The problem of cutting traffic to fake services per se: address writing, changes to hosts/configuration, and probably forgetting to cut back.
III. TRADITIONAL MOCK PERSPECTIVE: THE SPECIFIC SPECIFIC SPECIFIC INSTRUCTURE
The nature of the mock tool distinguishes between "doing at which level of the chain": the service border sham service (WireMock is the factual standard on the main line of this paper), the stake-laying process (single detection), the browser intercept (front end connection):
Several general tool layers that can be used regardless of product form:
- Process stakes (back-end singles, unserviceable): Java Mockito 5 (naturally supported status/final), byte Mackey; Python returns/respx; JS Jestmock. Ali TestableMock has been transferred to maintenance. limited-time has the right to co-operate with WireMock: a single test of pillar cover branches, a link to WireMock for real collaboration.
- Catcher / Agent: Charles, Fiddler fit for manual check; mimproxy can manipulate traffic with Python scripts and enter CI.
- Interface management platform: Apifox, Elink, ApiPost (interface document mock, birth HTTPS); ⚠️ Early years of RAP/RP2, YApi has been suspended for more years (YApi and historical loopholes), stock moved as soon as possible and no new items are selected.
- Flow recording: GoReplay, AREX, jvm-sandbox-repeater (the latter community version has not been substantially updated and the selection is based on maintenance activity).
- Consumer-driven compacts: Pact + Pact Broker, multi-team microservices are "modified" when the publish door is closed, instead of a link test.
-Mock LLM interface: The Open AI-style interface for LLM is also HTTPS, WireMock can stub its /v1/chat/complements.
Overall: Web/H5 desktop is the most economical, micro-service cut-off is the most elegant, small application card name list is the white list, and App (especially Anjo) certificates are the highest. WireMock can almost be covered, regardless of product form. There are only three alternatives: reliance on not HTTP (testcontainers), purely front-end independent connection (MSW/Apifox), multi-team microservices subject to publish doorbar.
IV. From 0 to CI: a mock landing line (manual approach)
The landing tool uses the WireMock - an independent fake HTTP server, which uses an out-of-sea advertising system throughout the example: the detected system will volunteer for the delivery of the service (GET /api/campaign/{id} (Radio project) and will be actively called back by the media POST/api/callback/conversion.
One thing from scratch: get your program to retransmit the original request to Google/Meta, payment, other team service to WireMock, which returns to normal, border, malfunction, timeout, etc., in accordance with pre-established rules — to simulate the downstream of those who are not in your control and who are called upon for testing. WireMock is an independent, fake HTTP server, and anyone who sends an HTTP request will answer it (Android, Java/Spring, Python, Node, NET, Go, Kubernetes, Testcontainers all of them in the official appliance list), without a pick-up, the rules will be matched only by "Method + Path + Paper." Want to use WireMock, which floor? There are only two standards, none of which relate to the form of the product:
HTTP: Walking HTTP is used on independent false servers such as WireMock (module tests can also be used to intercept within processes such as Mockito/Mockey, MSW/Nock); not to walk HTTP (database, Kafka, Redis), to rely on Testcontainers for real reliance and not to force mock.
- What level of measurement: pillaring in the unit test process, low value of WireMock; integration test from WireMock; small end-to-end real-down runs only happy path - catch CI, which will turn these three layers into two phases of the flow line.
This main line is fixed at the following 10 steps, and the mock of any interface is not rounded:
1 WireMock #2-trip flow #3 past HTTPS (as required)
Prepare asset 4 for contract 5 for first rule 6 for three layers of data
Execute 7 fault test retry → 8 Run case CI
In reverse.
Long-term drive, 10 protection against drift.
4.1 Step 1: Set your feet and run WireMock.
Amp on the real machine/simulator, WireMock on your PC, both with one WiFi:
Andre App - HTTPS - WireMock on PC (192.168.x:8443)
{\cHFFFFFF}{\cH00FFFF}{\cH00FFFF} Go back to the false ad plan / media sounds Response
Java 11+ (WireMock 3.x minimum requirement; only old 2.x also supports Java 8) is required to download wiremock-standardone-3.x.jar (a fat jar, zero dependent) and drive HTTP and HTTPS:
java -jar wiremock-standalone-3.x.jar --port 8080 --https-port 8443
A process serves both ports and the same set of rules. It is a standard HTTP(S) server, with App, web pages, micro-services and requests being the same and not the caller. Assuming that PC Intranet IP is 192,168.1.10, access to the mobile browser at http://192,168.1.10:8080/ admin opens the network to indicate whether PC firewalls, mobile phones and PCs are part of the network. The rule file is placed on the current directory mampings/, reloading automatically.
4.2 Step 2: Send the request to WireMock-App Three Cuts + Backend Environmental Variable
WireMock's up, but App defaults on sending requests to online domain names and has to reroute them. This step only addresses "how to change the course" and how the rules are written. App selects one by its recommended level:
- Preferred: A test package with a switchable baseURL is required to fill the interface domain directly in https://192.168.1.10:8443. This is a detectability requirement and is scheduled to follow the development, agent, hosts, certificate a half.
- Subselection: WiFi hanger (Charles/mitmproxy, then transferred to WireMock) suitable for temporary screening.
- Root devices changed hosts: Andre/system/etc/hosts add a line 192,168.1.10 api. Your downstream.com (PC end: C:\Windows\System32\drivers\eth\hosts) to interpret domain names to WireMock.
You don't think about the service, you just want the App page to have data quickly? There is also an inner path: the test kit Riga OkHttp Interceptor, the hit configuration is directly repackaged, unticked, and the request is unended. The cost is to bypass the real network and to prove faulty. The main line of this paper is WireMock, and the interceptor is only available when the page is connected.
The three solutions above are "App how to reroute" on the phone; instead of running on the back end of the server, it does not have a pointable baseURL set-up page or a mobile phone agent, it does not have access to a downstream address to read environmental variables/configuring files – as in App Law 1, by its very nature, it allows the address to be configured, but only in different places. It's in two places:
#1 measured side of service config.py: default value to real address, uncovered, and never real, natural "forgetting back into production"
AD_API_BASE = os.getenv("AD_API_BASE", "https://api.partner.com")
# 2 covered with WireMock from the test service, in this line
# Local manual connection: export AD API BASE=http://localhost:8080
# CI / docker-compose:
environment: [AD_API_BASE=http://wiremock:8080]
The manual coupling behind the CI automating is the same variable, but the injection is different. The off-site location is a serious back-end configuration (which also depends on production cut-offs) rather than a retrofit for testing; the development, even if it does not work, is returned to a network layer such as agent/hosts-DNS/ gateway/registration centre (zero change code at the cost of passing the following certificate level).
4.3 Step 3: Passing the HTTPS level (as required, App's most painful)
The real interface is HTTPS. WireMock itself fully supported HTTPS, which was never a tool, but instead allowed App to trust the certificate -- command line plus a k -- to skip the check, but not App. Pick one on your terms:
Series 1 Test package trust test CA (prescriptive, recommended). Let WireMock start the certificate with an internal test from CA:
java -jar wiremock-standalone-3.x.jar --https-port 8443 \
--https-keystore /certs/test-downstream.p12 \
Your password.
Anzor test package with network SecurityConfig, building trust in this CA (res/xml/network security config.xml):
<network-security-config>
<debug-overrides>
<trust-anchors>
<certificates src="system" />
<certificates src="@raw/test_ca" />
</trust-anchors>
</debug-overrides>
</network-security-config>
The 2 DEBUG package code temporarily trusts all certificates (the fastest, the highest risk). If you can't get the standard test kit, the core is:
/ / Test package only effective: Trust any certificate + Skip hostname verification
private static final X509TrustManager TRUST_ALL = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] c, String a) {}
public void checkServerTrusted(X509Certificate[] c, String a) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
};
static OkHttpClient.Builder bypassForMock(OkHttpClient.Builder b) throws Exception {
If(!BuildConfig.ENABLE DEBUG MOCK) return b; / / 🔒Savegate: not DEBUG packages return directly, never "trust all certificates"
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[]{TRUST_ALL}, new SecureRandom());
b.sslSocketFactory(sc.getSocketFactory(), TRUST_ALL)
.hostnameVerifier((host, sess) -> true);
return b;
}
🔴 has to be locked in a test package with a compilation period DEBUG switch, which by mistake is equivalent to turning off all HTTPS protection. No source code, only Frida / Xposed+JustTrustMe, and only app, controlled equipment.
Several App-specific pits:
- Certificate fixation (Pinning): App internalized server certificate fingerprints, even the CA was rejected and the test package had to be shut down;
- QUIC/HTTP3 Go UDP 443 will bypass TCP agents and test the network for UDP 443 to force it back to TCP;
- iOS does not have to write a code: after loading the description file, you have to set up a generic certificate trust setup, which is manually activated and is subject to the ATS restriction.
File 3 downstream is a two-way authentication mTLS - allowing WireMock to verify the client certificate in turn. Payment, finance, internal systems are common: not only App to mail servers but also to check App's client certificates. Let WireMock play this downstream, hang on the trust library and open the client certificate check:
java -jar wiremock-standalone-3.x.jar --https-port 8443 \
--https-keystore /certs/test-downstream.p12 --keystore-type PKCS12 \
--https-require-client-cert \
--https-truststore /certs/allowed-clients.p12 --truststore-type PKCS12
Could not close temporary folder: %s This in itself is a safety example to be measured.
File 4 downstream addresses are written as https without any trust configuration - use Nginx to unload TLS. Old App can neither change the package nor close the certificate, but downstream domain names can be pointed through hosts. Allow Nginx to access App in 443 using valid https (Certificate from Nginx and Add App Trust Library), declassified and explicitly transferred 8080 to WireMock, moving this certificate from the mock tool to Nginx - Note is not free of the certificate, the certificate still gives App confidence:
server {
listen 443 ssl;
# App to access downstream domain names
ssl certificate /certs/partner.crt; #addition to App Trust Library
ssl_certificate_key /certs/partner.key;
# If downstream is mTLS, add ssl verify client on; check client certificates by Nginx
location / {
Proxy pass http://127.0.0.1:8080; # Unmount TLS and explicitly transfer to WireMock
proxy_set_header Host $host;
}
}
Mosts point api.partner.com to this Nginx. The details of the fourth set of parameters can be compared with the WireMock official HTTPS document.
Three steps (service, cut-off, pass-of-certificate) are completed and the link is made. A simplest fake response to verify the success of the rerouting — exactly what the rules look like next step.
4.4 Step 4: Take a contract -- figure out what the interface looks like before writing the rules.
A lot of people come up and write fakes, JSON, and it turns out that field is a funded, money unit, and that's the pain. The truth about the interface before writing the rules (the line is "the contract" ) comes from a reliable sequence:
- The definition of parameters with the code permission: DTO / VO, controller is the most accurate source, with field names, types, mandatory entries, proofing notes;
- With interface documents: definitions in OpenAPI/Swagger, Apifox;
- Nothing at all: Charles/mitmproxy exported HAR to check out the real request for a response and then call the interface manager for an oral confirmation.
These noises are removed first and only the business interface is left. Manually, at least five of the interfaces should be on paper/forms, none of which can be guessed:
Item 5 is the most easily mined: the time zone and window of the time field must be closed and more often asked. This table is the common basis for writing rules, building data, making contractual locks. - The manual is self-filling, and the next chapter will see that AI can clean the HAR/C key into this table.
4.5 Step 5: Writing the first rule (mapping)
It's connected, it's contractual, it's written the first true rule, the end to the end. Onmappings/campaign.json put:
{
"request": { "method": "GET", "urlPathPattern": "/api/campaign/[0-9]+" },
"response": {
"status": 200,
"headers": { "Content-Type": "application/json" },
"JsonBody":
}
}
Opens the App's plan details page (or calls the detection system with curl/Postman) and it's this fake data -- the first closed loop. Every field in the rules is the last one on the contract: Butget is the whole number, Status has a confirmed count, and none of field is a headshot.
There are two sets of rules, chosen by purpose:
- mappings/catalogues: enter Git, assessable, reloadable, suitable for stable, long-standing rules;
- Run-time Admin API Dynamics: Admin API Dynamics: ad hoc filling, run-off and discarding in the case, suitable for each example ' s different failure/data:
curl -X POST http://192.168.1.10:8080/__admin/mappings \
-H 'Content-Type: application/json' -d @campaign.json
Multi-conditional rules can also be matched by header, query, body, or return different results for different entries.
4.6 Step 6: Three layers at a time - normal/ boundary / dirty
To create only a happy path is to verify that the system does not collapse when everything goes well. Real defects and damages are almost all hidden in border and dirty data (pity point 6). Manual approach: The data from the same interface are divided into three groups at the equivalent price around the previous contract and are made article by article and passed over to the detected system:
C is the focus of the focus: a dirty data collection is a true Bug (floating point amount, illegal count, private addition of field is the highest three types of distribution, and Bull is the int subcategory and the hidden item of the amount unit is specially designed).
A few pieces can be made manually, but batching is slow and easy to create. Two landing approaches:
- Few data: written directly at mapping jsonbody, or a scene with a maping file;
- Batch of data: use bodyFileName references in files/ directory storage JSON, mapping; or write a script running through the data file, each walking Admin API dynamic.
This step is the largest gap between manual and AI: People make up 5 strips of business-related data, and AI plus Faker can bring hundreds of field connections at a time — the next chapter is available for prompt. But the manual also has to understand the three levels of justice, otherwise AI can't judge right or wrong.
4.7 Step 7: Faults and anomalies, verification of retry and tolerance errors
It is not enough to have normal/boundary data alone that WireMock, the most valuable of which is not a business code, can simulate a downstream winding, all in respone: rate limit/service error "status": 429 or 500; timeout "fixed Delay Milliseconds": 5,000; broken/mutilated response "failed": "CONNECTION RESET BY PEER"/ "MALFORMED RESPONSE CHUNK".
Focus on the state of "first two failures, third success" - to verify the logic of the detected system retry, using Scenarios. Place three rules in the following document:
{
"mappings": [
{ "scenarioName": "retry-then-success", "requiredScenarioState": "Started",
"newScenarioState": "r1",
"request": { "method": "GET", "urlPath": "/api/campaign/1001" },
"response": { "status": 500 } },
{ "scenarioName": "retry-then-success", "requiredScenarioState": "r1",
"newScenarioState": "r2",
"request": { "method": "GET", "urlPath": "/api/campaign/1001" },
"response": { "status": 500 } },
{ "scenarioName": "retry-then-success", "requiredScenarioState": "r2",
"request": { "method": "GET", "urlPath": "/api/campaign/1001" },
"response": { "status": 200,
"JsonBody": {"campaign id": 1001, "name": "test ad plan", "status": "ACTIVE"}
]
}
When a group with a status rule is placed in the same file under mappings/, the outer layer must contain a layer {“mappings”:[ ]}, which cannot be thrown directly at a nudity array (the nudity array is valid only in the batch import interface POST / admin/mappings/import; the file is not loaded). Note: None of the rules for loading from mapings/files is suitable for dynamic additions or deletions in scripts (document rules are enough, heat loads are sufficient); for example to be built or discarded, Admin API - a single POST / admin/mappings, or a one-time POST / admin/mappings/import pass { "mappings":[ ]].
How does it prove that the system really is retry? Ask WireMock to "tweet":
curl -X POST http://192.168.1.10:8080/__admin/requests/count \
-H 'Content-Type: application/json' \
-d '{"method":"GET","urlPath":"/api/campaign/1001"}'
returns {count:3} is a three-time proof of retry; plus a "Hand 500" to verify retry to the upper limit when the system gives a failure warning and stops at the upper limit. retry, melting, is the system's own behavior, and WireMock returns only by script, and you are responsible only for the number of times, not for retry in the mock.
4.8 Step 8: Run examples, feed automation and CI
This step settles it into automatic return and enters the CI. The technology stack is based on Python + Pytest + references + docker community, and the idea is common to any language.
This step is a later service-form demonstration. The rationale is practical: CI is unattended, ready to start from zero in a clean environment, with a back end docker copose up that can get WireMock together with the detected service, downstream addresses injected with environmental variables, and deploys the same code once each of the two phases — the lightest, everybody can repeat; App also needs to prepare simulators/real machines, test kits, running Appium, heavy and unstable, not suitable for minimum demonstration. But the usage of the WireMock side has nothing to do with the detected morphology: the following "pytest straight-to-detect service" was tested on Appium/Espresso instead of the test kit that pointed to WireMock. The rules, the Admin API control channel, the number of toddlers are not changed.
Here's to go in the order of 1 set of projects 2 set up for 3 set of survey services 4 written for example →5 file traffic 6 run local two-stage run 7 plus CI, each with a complete file and running by a catalogue and code.
1 Set out the project catalogue. This is the least possible way to run the project.
mock-demo/
Docker-compose.yml # ShapeMock + Tested Service
Ideas - svc/ # Example of measured services
# Read AD API BASE forward downstream with retry
│ └── Dockerfile
Ideas -wiremock/mappings/ # Stability rules can be rolled in Git
└── tests/
Ideas -contest.py # and WireMock/ Public Plugin for the detected system (two channels + reset)
Ideas -test normal.py
Ideas -test fault.py # Malfunction case (mock mark)
└-test smoke real.py # True downstream smoke (real mark + default sskip)
2 Into the detection service. This is the back end of the real project, where you use the standard library to write a zero-dependency minimum double, which is only two things: Read downstream addresses from environmental variables ( "outside address" according to step 2 main line) and downstream 5xx up to retry 3 times (just validated by example of failure in the back). New svc/app.py:
#svc/app.py - a minimum detector service that relays downstream with retry
import json, os, time, urllib.request, urllib.error
from http.server import BaseHTTPRequestHandler, HTTPServer
AD API BASE = os.getenv
MAX_RETRY = 3
def call_downstream(campaign_id):
url = f"{AD_API_BASE}/api/campaign/{campaign_id}"
for _ in range(MAX_RETRY):
try:
with urllib.request.urlopen(url, timeout=5) as r:
return r.status, r.read().decode()
# Return downstream 500 will enter here
if 500 <= e.code < 600:
# The real project is a retreat strategy.
continue
return e.code, e.read().decode()
except Exception:
time.sleep(0.1)
return 503, json.dumps({"error": "downstream unavailable after retries"})
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path.startswith("/campaigns/"):
cid = self.path.rsplit("/", 1)[-1]
status, body = call_downstream(cid)
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.end_headers
Auto-fetched and translated by AI Atlas. All rights belong to the original author.