dever-labs/mockly
GitHub: dever-labs/mockly
这是一款跨平台、支持多种协议(HTTP、gRPC、Redis 等)的 Mock 服务器,提供 Web UI 和故障注入功能,专为组件测试与 CI 集成设计。
Stars: 0 | Forks: 0
# Mockly
**跨平台、多协议 mock 服务器** — HTTP、WebSocket、gRPC、GraphQL、TCP、Redis、SMTP 和 MQTT 合并为单一二进制文件,内置 Web UI、REST 管理 API、场景系统和故障注入。
[](https://github.com/dever-labs/mockly/actions/workflows/ci.yml)
[](https://github.com/dever-labs/mockly/releases/latest)
[](LICENSE)
## 目录
- [功能](#features)
- [快速开始](#quickstart)
- [配置](#configuration)
- [协议](#protocols)
- [组件测试](#component-testing)
- [场景](#scenarios)
- [故障注入](#fault-injection)
- [PATCH Mocks](#patch-mocks)
- [预设配置](#preset-configs)
- [CLI 参考](#cli-reference)
- [管理 API 参考](#management-api-reference)
- [客户端库](#client-libraries)
- [CI 集成](#ci-integration)
- [架构](#architecture)
- [开发](#development)
- [贡献](#contributing)
- [许可证](#license)
## 功能
| 功能 | 详情 |
|---|---|
| **协议** | HTTP, WebSocket, gRPC, GraphQL, TCP, Redis, SMTP, MQTT |
| **请求匹配** | Method + path(精确 / 通配符 / 正则),headers,query params,JSON body 字段 |
| **响应序列** | 每次连续调用返回不同的响应 — 循环、保持最后一个或用尽后返回 404 |
| **响应控制** | 状态码、headers、body、人工延迟 |
| **模板响应** | 响应体中使用 Go 模板语法(`{{now}}`、`{{.body}}` 等) |
| **状态条件** | 仅当运行时状态变量匹配时触发 mock |
| **场景** | 命名的 mock patch 集合 — 通过 API 或 CLI 原子激活/停用 |
| **全局故障注入** | 对所有请求施加延迟、状态覆盖和概率性错误率 |
| **单 mock 故障注入** | 单个 mock 上的故障字段 — 独立于全局故障 |
| **调用验证** | 跟踪每个 mock 被命中的次数;阻塞直到达到预期次数 |
| **PATCH mocks** | 在运行时仅更改特定的响应字段,无需替换整个 mock |
| **预设配置** | 针对 Keycloak、Authelia、OAuth2、GitHub、Stripe、OpenAI、Slack、Twilio、SendGrid 的即插即用 YAML 配置 |
| **Web UI** | 由二进制文件自身提供服务 — 无需单独安装 |
| **管理 API** | 40+ REST 端点,覆盖所有协议、场景、故障、状态、日志和调用计数 |
| **实时请求日志** | 通过 SSE 实时流式传输到 UI |
| **CI 友好** | 零依赖、单一二进制、YAML 配置、Docker 镜像 |
## 快速开始
### 下载
从 [releases page](https://github.com/dever-labs/mockly/releases) 获取适用于你平台的二进制文件,或从源码构建:
```
git clone https://github.com/dever-labs/mockly
cd mockly
make build # builds UI + Go binary
```
### 使用配置文件运行
```
mockly start --config mockly.yaml
```
打开 `http://localhost:9091` 访问 Web UI,或在同一端口调用管理 API。
### 运行预设
```
mockly preset use keycloak # starts Mockly pre-loaded with Keycloak endpoints
mockly preset list # list all available presets
mockly preset show stripe # print the preset YAML
```
## 配置
Mockly 由 YAML 配置文件驱动。每个部分都是可选的。
```
mockly:
api:
port: 9091 # Management API + Web UI port (default: 9091)
protocols:
http:
enabled: true
port: 8080
mocks:
- id: list-users
request:
method: GET
path: /api/users
response:
status: 200
headers:
Content-Type: application/json
body: '[{"id":1,"name":"Alice"}]'
delay: 50ms
websocket:
enabled: true
port: 8081
mocks:
- id: echo
path: /ws/echo
on_message:
match: ping
respond: pong
grpc:
enabled: true
port: 50051
services:
- name: users
mocks:
- id: get-user
method: GetUser
response:
body: '{"id":"1","name":"Alice"}'
graphql:
enabled: true
port: 8082
path: /graphql
mocks:
- id: get-user
operation_type: query
operation_name: GetUser
response:
user:
id: "1"
name: Alice
tcp:
enabled: true
port: 8083
mocks:
- id: hello
pattern: "HELLO"
response: "WORLD\n"
redis:
enabled: true
port: 6379
mocks:
- id: get-session
command: GET
key: "session:*"
response:
type: bulk
value: '{"userId":"abc"}'
smtp:
enabled: true
port: 2525
domain: mockly.local
rules:
- id: accept-all
action: accept
mqtt:
enabled: true
port: 1883
mocks:
- id: sensor-ack
topic: "sensors/+"
response:
topic: "sensors/ack"
payload: '{"ok":true}'
scenarios:
- id: auth-down
name: Auth Service Down
description: Simulate auth outage — all token endpoints return 503
patches:
- mock_id: list-users
status: 503
body: '{"error":"auth unavailable"}'
```
### 路径匹配
| 模式 | 匹配 |
|---|---|
| `/api/users` | 精确匹配 |
| `/api/*` | 任何以 `/api/` 开头的路径 |
| `re:^/users/\d+$` | 正则 — 任何 `/users/` |
### 模板响应
响应体作为 Go 模板渲染。内置函数:
| 函数 | 示例 | 描述 |
|---|---|---|
| `{{now}}` | `2024-01-15T10:30:00Z` | 当前 UTC 时间(RFC3339) |
| `{{date "2006-01-02"}}` | `2024-01-15` | Go 格式的当前日期 |
| `{{date_add "2006-01-02" "-7d"}}` | `2024-01-08` | 带持续时长偏移的日期 |
| `{{uuid}}` | `550e8400-e29b-41d4-a716-446655440000` | 随机 UUID v4 |
| `{{rand_int 1 100}}` | `42` | [min, max] 范围内的随机整数 |
| `{{rand_float 0.0 1.0 2}}` | `0.73` | 带有 N 位小数的随机浮点数 |
| `{{rand_string 8}}` | `aB3xKp7m` | 随机字母数字字符串 |
| `{{rand_string 8 "hex"}}` | `3f9a1c2b` | 字符集:`alpha`、`lower`、`upper`、`numeric`、`hex`、`alphanumeric` 或自定义 |
| `{{rand_bool}}` | `true` | 随机布尔值 |
| `{{pick "a" "b" "c"}}` | `b` | 随机选取给定值之一 |
| `{{fake "name"}}` | `Alice Smith` | 伪造全名 |
| `{{fake "email"}}` | `alice.smith@example.com` | 伪造邮箱 |
| `{{fake "phone"}}` | `+1-555-0142` | 伪造电话号码 |
| `{{fake "company"}}` | `Apex Labs` | 伪造公司名称 |
| `{{fake "city"}}` | `Berlin` | 伪造城市 |
| `{{fake "country"}}` | `Germany` | 伪造国家 |
| `{{fake "street"}}` | `42 Main St` | 伪造街道地址 |
| `{{fake "zip"}}` | `10115` | 伪造邮政编码 |
| `{{fake "ip"}}` | `192.168.1.42` | 伪造 IPv4 |
| `{{fake "ipv6"}}` | `2001:db8::1a2b:3c4d` | 伪造 IPv6 |
| `{{fake "url"}}` | `https://apex.io/api/lorem` | 伪造 URL |
| `{{fake "username"}}` | `alice42` | 伪造用户名 |
| `{{fake "useragent"}}` | `Mozilla/5.0 …` | 随机 User-Agent 字符串 |
| `{{fake "word"}}` | `lorem` | 单个 lorem ipsum 单词 |
| `{{fake "sentence"}}` | `lorem ipsum dolor sit amet` | 短 lorem ipsum 短语 |
| `{{seq "counter"}}` | `1`, `2`, `3`, … | 按命名计数器自动递增的整数 |
| `{{lorem 5}}` | `lorem ipsum dolor sit amet` | N 个 lorem ipsum 单词 |
| `{{upper "hello"}}` | `HELLO` | 大写字符串 |
| `{{lower "WORLD"}}` | `world` | 小写字符串 |
| `{{.body}}` | *(请求体)* | 传入的请求体 |
| `{{.headers.X-Foo}}` | *(header 值)* | 传入的请求 header |
| `{{state "key"}}` | *(状态值)* | 来自运行时状态存储的值 |
**序列计数器**(`{{seq "name"}}`)会通过 `POST /api/reset` 或 `mockly reset` 重置为零。
示例 — 在每次请求时生成逼真的用户对象:
```
response:
status: 200
headers:
Content-Type: application/json
body: |
{
"id": "{{uuid}}",
"name": "{{fake "name"}}",
"email": "{{fake "email"}}",
"role": "{{pick "user" "admin" "viewer"}}",
"score": {{rand_float 0 100 1}},
"created_at": "{{now}}"
}
```
## 协议
### HTTP
完整的 HTTP mock 服务器。匹配 method + path(精确/通配符/正则)、可选 query params、header 匹配、JSON body 字段匹配和状态条件。
```
protocols:
http:
enabled: true
port: 8080
mocks:
- id: create-user
request:
method: POST
path: /users
headers:
Authorization: "Bearer *"
response:
status: 201
body: '{"id":"{{uuid}}"}'
headers:
Content-Type: application/json
delay: 20ms
```
#### Query 参数匹配
```
- id: admin-users
request:
method: GET
path: /users
query:
role: admin # exact match
page: "*" # any value (wildcard)
response:
status: 200
body: '[{"id":1,"role":"admin"}]'
```
#### JSON body 字段匹配
使用点符号路径匹配 JSON body 中任意位置的字段:
```
- id: gbp-payment
request:
method: POST
path: /payments
body_json:
currency: GBP # exact
"user.tier": premium # nested: {"user":{"tier":"premium"}}
"items.0.sku": "*" # any SKU (wildcard)
response:
status: 200
body: '{"ok":true}'
```
#### 响应序列
每次连续调用返回不同的响应。适用于模拟瞬时错误或分页。
```
- id: flaky-service
request:
method: GET
path: /data
sequence:
- status: 503
body: '{"error":"unavailable"}'
- status: 503
body: '{"error":"unavailable"}'
- status: 200
body: '{"data":"ok"}'
sequence_exhausted: hold_last # hold_last (default) | loop | not_found
response:
status: 200
body: '{"data":"ok"}'
```
| `sequence_exhausted` | 所有条目被消耗后的行为 |
|---|---|
| `hold_last` | 保持返回最后一个条目(默认) |
| `loop` | 从第一个条目重新开始 |
| `not_found` | 返回 404 |
#### 单 mock 故障注入
每个 mock 都可以有自己的 `fault:` 块 — 独立于全局故障:
```
- id: slow-search
request:
method: GET
path: /search
fault:
delay: 2s # add latency
status_override: 429 # replace status code
body: '{"error":"rate limited"}'
error_rate: 0.5 # only apply 50% of the time (0 = always)
response:
status: 200
body: '[]'
```
### WebSocket
```
protocols:
websocket:
enabled: true
port: 8081
mocks:
- id: ticker
path: /ws/ticker
on_connect:
send: '{"type":"connected"}'
on_message:
match: subscribe
respond: '{"type":"tick","price":42.0}'
```
### gRPC
动态 gRPC mock — 无需编译 `.proto` 文件。使用原始编解码器拦截任何服务/方法调用。
```
protocols:
grpc:
enabled: true
port: 50051
services:
- name: payments
mocks:
- id: charge
method: Charge
response:
body: '{"success":true,"charge_id":"ch_123"}'
```
### GraphQL
基于 HTTP 的 GraphQL mock。处理 `POST /graphql` 的 `application/json` 和 `application/graphql` 内容类型,以及带有 `query` 参数的 `GET` 请求。内省查询返回空 schema。
```
protocols:
graphql:
enabled: true
port: 8082
path: /graphql
mocks:
- id: create-post
operation_type: mutation
operation_name: CreatePost
response:
createPost:
id: "{{uuid}}"
title: Hello
errors: []
```
### TCP
原始 TCP mock 服务器。将传入数据匹配为精确字符串、前缀通配符或正则。支持二进制协议的十六进制编码。
```
protocols:
tcp:
enabled: true
port: 8083
mocks:
- id: ping
pattern: "PING\r\n"
response: "+PONG\r\n"
- id: hex-response
pattern: "re:^\\x02.*\\x03$"
response_hex: "060000"
```
### Redis
RESP 协议 Redis mock。拦截任何 Redis 命令并返回可配置的响应。
```
protocols:
redis:
enabled: true
port: 6379
mocks:
- id: auth
command: AUTH
response:
type: string # string | bulk | integer | null | error | array
value: "OK"
- id: get-token
command: GET
key: "token:*"
response:
type: bulk
value: "abc123"
delay: 5ms
```
### SMTP
捕获邮件并应用接受/拒绝规则的 SMTP 服务器。
```
protocols:
smtp:
enabled: true
port: 2525
domain: mockly.local
rules:
- id: reject-spam
from: "*@spam.example.com"
action: reject
message: "550 spam not accepted"
- id: accept-all
action: accept
```
捕获的邮件可在 `GET /api/emails` 查看。
### MQTT
完整的 MQTT v3/v4/v5 broker(由 mochi-mqtt 驱动)。可配置的主题模式匹配,并自动发布响应。
```
protocols:
mqtt:
enabled: true
port: 1883
mocks:
- id: command-ack
topic: "devices/+/command"
response:
topic: "devices/+/ack"
payload: '{"status":"ok"}'
qos: 1
```
主题通配符:`+` 匹配单个段,`#` 匹配其下所有内容。
## 组件测试
Mockly 专为 **组件测试** 设计 — 测试当依赖项返回错误、超时、意外数据或边缘情况响应时,你的应用程序如何表现。配置文件由依赖团队维护;使用团队只需加载它并切换场景。
### 典型工作流
```
dependency-service/
└── mockly/
├── mockly.yaml # base happy-path mocks
└── scenarios/ # optional split-out scenario files
├── auth-down.yaml
└── payment-timeout.yaml
```
你的测试:
```
// start mockly with the dependency's config
// activate a scenario to simulate a failure
// make requests to your app and assert it handles the error correctly
// call the verification API to confirm your app called the right endpoints
```
### 调用验证
检查你的应用命中 mock 的次数 — 无需抓取日志:
```
# POST /token 被调用了多少次?
curl http://localhost:9091/api/calls/http/token-endpoint
# 阻塞直到 mock 至少被调用 3 次(超时 5s)
curl -X POST http://localhost:9091/api/calls/http/token-endpoint/wait \
-H 'Content-Type: application/json' \
-d '{"count":3,"timeout":"5s"}'
# 重置单个 mock 的调用计数器
curl -X DELETE http://localhost:9091/api/calls/http/token-endpoint
# 重置所有调用计数器
curl -X DELETE http://localhost:9091/api/calls/http
```
来自 `GET /api/calls/http/{mockId}` 的响应:
```
{
"mock_id": "token-endpoint",
"count": 3,
"calls": [
{"id": "...", "mock_id": "token-endpoint", "method": "POST", "path": "/token", "timestamp": "..."}
]
}
```
### 完整组件测试示例
```
protocols:
http:
enabled: true
port: 8080
mocks:
# Happy path
- id: get-token
request:
method: POST
path: /oauth/token
body_json:
grant_type: client_credentials
response:
status: 200
body: '{"access_token":"{{uuid}}","expires_in":3600}'
# Sequence: simulate token refresh after expiry
- id: get-token-expiry-flow
request:
method: POST
path: /oauth/token
body_json:
grant_type: refresh_token
sequence:
- status: 401
body: '{"error":"token_expired"}'
- status: 200
body: '{"access_token":"new-token","expires_in":3600}'
sequence_exhausted: hold_last
response:
status: 200
body: '{"access_token":"new-token","expires_in":3600}'
scenarios:
- id: auth-service-down
name: Auth Service Down
patches:
- mock_id: get-token
status: 503
body: '{"error":"service unavailable"}'
- id: rate-limited
name: Rate Limited
patches:
- mock_id: get-token
status: 429
body: '{"error":"too_many_requests"}'
```
## 场景
场景允许你预定义命名的 mock 覆盖,并随时激活/停用它们 — 非常适合在测试期间切换正常路径和故障模式。
### 在配置中定义
```
scenarios:
- id: payment-timeout
name: Payment Gateway Timeout
patches:
- mock_id: charge
status: 504
body: '{"error":"timeout"}'
delay: 5s
- mock_id: refund
disabled: true # Removes this endpoint entirely
```
### 通过 CLI 控制
```
mockly scenario list
mockly scenario activate payment-timeout
mockly scenario deactivate payment-timeout
```
### 通过 API 控制
```
# 激活
curl -X POST http://localhost:9091/api/scenarios/payment-timeout/activate
# 停用
curl -X DELETE http://localhost:9091/api/scenarios/payment-timeout/activate
# 列出激活项
curl http://localhost:9091/api/scenarios/active
```
## 故障注入
注入全局故障以测试应用程序的弹性 — 无需触及单个 mock。
```
# 为所有请求注入 100ms 延迟
mockly fault set --delay 100ms
# 使 30% 的请求返回 503
mockly fault set --status 503 --rate 0.3
# 始终返回 429(速率限制)
mockly fault set --status 429
# 移除故障
mockly fault clear
```
或通过 API:
```
curl -X POST http://localhost:9091/api/fault \
-H 'Content-Type: application/json' \
-d '{"enabled":true,"delay":"100ms","status_override":503,"error_rate":0.3}'
curl -X DELETE http://localhost:9091/api/fault
```
故障字段:
| 字段 | 类型 | 描述 |
|---|---|---|
| `enabled` | bool | 总开关 |
| `delay` | duration | 在匹配之前为每个请求添加的延迟 |
| `status_override` | int | 匹配后替换响应状态 |
| `error_rate` | float | 覆盖触发的概率(0–1);0 = 总是 |
## PATCH Mocks
更改现有 mock 的单个字段,无需完全替换它:
```
curl -X PATCH http://localhost:9091/api/mocks/http/charge \
-H 'Content-Type: application/json' \
-d '{"response":{"status":500,"body":"{\"error\":\"internal\"}"}}'
```
## 预设配置
Mockly 附带了针对常见服务的预构建 YAML 配置:
| 预设 | 描述 |
|---|---|
| `keycloak` | Token 端点、JWKS、userinfo、内省 |
| `authelia` | Auth 验证、session 端点 |
| `oauth2` | 通用 OAuth2 流程(authorize、token、revoke) |
| `github` | REST API:repos、issues、pull requests |
| `stripe` | Charges、refunds、customers、payment intents |
| `openai` | Chat completions、embeddings、models |
| `slack` | Messages、channels、users、reactions |
| `twilio` | SMS、calls、lookup |
| `sendgrid` | Email send、templates、contacts |
每个预设还包含针对常见故障模式的内置场景(例如 `keycloak-unauthorized`、`stripe-card-declined`)。
### 使用预设
```
mockly preset use keycloak
```
### 将预设导入你自己的配置
```
mockly preset show keycloak > keycloak.yaml
# 编辑 keycloak.yaml,然后:
mockly start --config keycloak.yaml
```
## CLI 参考
```
mockly start [--config ] [--http-port ] [--api-port ]
mockly apply --config
mockly list
mockly add http --method GET --path /foo --status 200 --body '{"ok":true}'
mockly delete
mockly status
mockly reset
mockly preset list | show | use
mockly scenario list | show | activate | deactivate
mockly fault set [--delay ] [--status ] [--rate ] | clear | show
```
## 管理 API 参考
Base URL: `http://localhost:9091`
### 协议
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET | `/api/protocols` | 列出所有协议状态 |
| `GET` | `/api/health` | 健康检查 |
### HTTP Mocks
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/api/mocks/http` | 列出 HTTP mocks |
| `POST` | `/api/mocks/http` | 创建 HTTP mock |
| `PUT` | `/api/mocks/http/{id}` | 替换 HTTP mock |
| `PATCH` | `/api/mocks/http/{id}` | 部分更新 HTTP mock |
| `DELETE` | `/api/mocks/http/{id}` | 删除 HTTP mock |
WebSocket (`/api/mocks/websocket`)、gRPC (`/api/mocks/grpc`)、GraphQL (`/api/mocks/graphql`)、TCP (`/api/mocks/tcp`)、Redis (`/api/mocks/redis`)、SMTP (`/api/mocks/smtp`)、MQTT (`/api/mocks/mqtt`) 同理。
### 调用验证 (HTTP)
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/api/calls/http/{mockId}` | 获取 mock 的调用计数 + 日志条目 |
| `POST` | `/api/calls/http/{mockId}/wait` | 阻塞直到 mock 被调用 N 次(body:`{"count":N,"timeout":"5s"}`) |
| `DELETE` | `/api/calls/http/{mockId}` | 清除 mock 的日志条目 + 重置所有 HTTP 调用计数 |
| `DELETE` | `/api/calls/http` | 清除所有 HTTP 日志条目并重置所有调用计数 |
### 邮箱收件箱 (SMTP)
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/api/emails` | 列出捕获的邮件 |
| `DELETE` | `/api/emails` | 清空收件箱 |
### MQTT 消息
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/api/mqtt/messages` | 列出捕获的 MQTT 消息 |
| `DELETE` | `/api/mqtt/messages` | 清空消息存储 |
### 场景
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/api/scenarios` | 列出所有场景 |
| `POST` | `/api/scenarios` | 创建场景 |
| `GET` | `/api/scenarios/active` | 列出活动场景 |
| `GET` | `/api/scenarios/{id}` | 获取场景 |
| `PUT` | `/api/scenarios/{id}` | 替换场景 |
| `DELETE` | `/api/scenarios/{id}` | 删除场景 |
| `POST` | `/api/scenarios/{id}/activate` | 激活场景 |
| `DELETE` | `/api/scenarios/{id}/activate` | 停用场景 |
### 故障注入
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/api/fault` | 获取当前故障配置 |
| `POST` | `/api/fault` | 设置故障配置 |
| `DELETE` | `/api/fault` | 清除故障 |
### 状态存储
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/api/state` | 获取所有状态键 |
| `POST` | `/api/state` | 设置状态键(JSON 对象) |
| `DELETE` | `/api/state/{key}` | 删除状态键 |
### 日志
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/api/logs` | 获取最近的日志条目 |
| `DELETE` | `/api/logs` | 清除日志 |
| `GET` | `/api/logs/stream` | 实时日志条目的 SSE 流 |
### 重置
| 方法 | 路径 | 描述 |
|---|---|---|
| `POST` | `/api/reset` | 将所有 mocks/状态/日志/故障/场景重置为配置默认值 |
## 客户端库
Mockly 提供官方客户端,为你管理进程生命周期、端口分配和管理 API — 让测试保持整洁和可移植。
| 语言 | 包 | 安装 |
|---|---|---|
| **Go** | `github.com/dever-labs/mockly/clients/go` | `go get github.com/dever-labs/mockly/clients/go` |
| **Node.js / TypeScript** | `@dever-labs/mockly-driver` | `npm i -D @dever-labs/mockly-driver` |
| **Java** | `io.github.dever-labs:mockly-driver` | 见下文 Maven/Gradle |
| **.NET / C#** | `Mockly.Driver` | `dotnet add package Mockly.Driver` |
| **Python** | `mockly-driver` | `pip install mockly-driver` |
| **Rust** | `mockly-driver` | 在 `[dev-dependencies]` 中添加 `mockly-driver = "0.4"` |
所有客户端:
- 自动查找或安装适用于当前平台的 Mockly 二进制文件
- 原子分配两个空闲端口(无 TOCTOU 竞争)
- 端口冲突时重试启动最多 3 次
- 暴露相同的概念:`addMock`、`activateScenario`、`setFault`、`reset`、`stop`
### Go
```
import mocklydriver "github.com/dever-labs/mockly/clients/go"
server, err := mocklydriver.Ensure(mocklydriver.Options{}, mocklydriver.InstallOptions{})
defer server.Stop()
server.AddMock(mocklydriver.Mock{
ID: "get-user",
Request: mocklydriver.Request{Method: "GET", Path: "/users/1"},
Response: mocklydriver.Response{Status: 200, Body: `{"id":1}`},
})
// server.HTTPBase = "http://127.0.0.1:"
```
[→ 完整 Go 文档](docs/clients/go.md)
### Node.js / TypeScript
```
import { MocklyServer } from '@dever-labs/mockly-driver'
const server = await MocklyServer.ensure()
await server.addMock({
id: 'get-user',
request: { method: 'GET', path: '/users/1' },
response: { status: 200, body: '{"id":1}' },
})
// server.httpBase = "http://127.0.0.1:"
await server.stop()
```
[→ 完整 Node.js 文档](docs/clients/node.md)
### Java
```
io.github.dever-labs
mockly-driver
0.4.7
test
```
```
try (MocklyServer server = MocklyServer.ensure(MocklyConfig.builder().build())) {
server.addMock(Mock.builder("get-user",
MockRequest.builder("GET", "/users/1").build(),
MockResponse.builder(200).body("{\"id\":1}").build()
).build());
// server.httpBase = "http://127.0.0.1:"
}
```
[→ 完整 Java 文档](docs/clients/java.md)
### .NET / C#
```
dotnet add package Mockly.Driver
```
```
await using var server = await MocklyServer.CreateAsync();
await server.AddMockAsync(new Mock {
Id = "get-user",
Request = new MockRequest { Method = "GET", Path = "/users/1" },
Response = new MockResponse { Status = 200, Body = """{"id":1}""" },
});
// server.HttpBase = "http://127.0.0.1:"
```
[→ 完整 .NET 文档](docs/clients/dotnet.md)
### Python
```
pip install mockly-driver
```
```
from mockly_driver import MocklyServer, Mock, MockRequest, MockResponse
server = MocklyServer.ensure()
server.add_mock(Mock(
id="get-user",
request=MockRequest(method="GET", path="/users/1"),
response=MockResponse(status=200, body='{"id":1}'),
))
# server.http_base = "http://127.0.0.1:"
server.stop()
```
[→ 完整 Python 文档](docs/clients/python.md)
### Rust
```
[dev-dependencies]
mockly-driver = "0.4"
```
```
let mut server = MocklyServer::ensure(ServerOptions::default(), Default::default()).unwrap();
server.add_mock(&Mock {
id: "get-user".into(),
request: Request { method: "GET".into(), path: "/users/1".into(), ..Default::default() },
response: Response { status: 200, body: Some(r#"{"id":1}"#.into()), ..Default::default() },
}).unwrap();
// server.http_base = "http://127.0.0.1:"
```
[→ 完整 Rust 文档](docs/clients/rust.md)
## CI 集成
Mockly 是一个无运行时依赖的单一静态二进制文件 — 非常适合 CI。
### GitHub Actions (composite action)
```
steps:
- uses: actions/checkout@v5
- name: Start Mockly
uses: dever-labs/mockly/.github/actions/setup-mockly@v0.4.7
with:
version: v0.4.7 # pin to a specific version
config: mockly.yaml # path to your config
api-port: 9090 # management API port (default)
- name: Run tests
run: npm test
```
该 action 自动:
- 下载适用于 runner OS/arch 的正确二进制文件
- 在后台启动 mockly
- 等待最多 30 秒直到服务器就绪
- 作业完成后终止进程
### GitLab CI
包含模板并扩展 `.mockly-start` 作业:
```
include:
- remote: 'https://raw.githubusercontent.com/dever-labs/mockly/main/.gitlab/mockly.yml'
integration-tests:
extends: .mockly-start
variables:
MOCKLY_VERSION: "v0.4.7"
MOCKLY_CONFIG: "mockly.yaml"
script:
- ./run-tests.sh
```
或将其作为 Docker 服务运行(无需安装二进制文件):
```
integration-tests:
image: alpine:3.21
services:
- name: ghcr.io/dever-labs/mockly:latest
alias: mockly
variables:
# mount config via CI artifacts or inline
variables:
MOCKLY_URL: http://mockly:9090
script:
- apk add --no-cache curl
- curl "$MOCKLY_URL/api/protocols"
- ./run-tests.sh
```
### 任何 CI (安装脚本)
```
# 安装最新版本
curl -sSfL https://raw.githubusercontent.com/dever-labs/mockly/main/install.sh | bash
# 或固定到特定版本
MOCKLY_VERSION=v0.2.0 \
curl -sSfL https://raw.githubusercontent.com/dever-labs/mockly/main/install.sh | bash
# 在后台启动并等待就绪
mockly start -c mockly.yaml &
until curl -sf http://localhost:9090/api/protocols; do sleep 1; done
```
### Docker
```
# 使用本地配置运行
docker run --rm \
-v "$PWD/mockly.yaml:/config/mockly.yaml:ro" \
-p 8080:8080 -p 9090:9090 \
ghcr.io/dever-labs/mockly:latest
# 或使用 docker compose
docker compose up
```
## 架构
```
┌──────────────────────────────────────────────────────────────────────────────────┐
│ Single Binary │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Management API + Web UI :9091 │ │
│ │ CRUD mocks/rules · scenarios · fault · state · logs/SSE │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────┐ ┌─────────┐ ┌──────┐ ┌─────────┐ ┌─────┐ ┌───────┐ ┌──────┐ ┌──────┐ │
│ │ HTTP │ │WebSocket│ │ gRPC │ │GraphQL │ │ TCP │ │ Redis │ │ SMTP │ │ MQTT │ │
│ │:8080 │ │ :8081 │ │:50051│ │ :8082 │ │:8083│ │ :6379 │ │:2525 │ │:1883 │ │
│ └──────┘ └─────────┘ └──────┘ └─────────┘ └─────┘ └───────┘ └──────┘ └──────┘ │
│ │
│ Shared: State Store · Request Logger · Scenario Store │
└──────────────────────────────────────────────────────────────────────────────────┘
```
## 开发
```
make build # build UI + Go binary
make test # run unit + integration tests
make test-e2e # run e2e tests (builds binary first)
make lint # run golangci-lint
make dev # hot-reload with air
```
完整的设置说明、提交约定和 PR 流程请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
## 贡献
欢迎贡献 — 错误报告、功能请求、预设配置和代码。
在提交 pull request 之前,请阅读 [CONTRIBUTING.md](CONTRIBUTING.md)。
参与即表示你同意遵守 [行为准则](CODE_OF_CONDUCT.md)。
对于安全问题,请遵循 [SECURITY.md](
标签:API模拟, EVTX分析, GraphQL, gRPC, Mock服务器, Python工具, Redis, RESTful API, SMTP, SOC Prime, TCP, WebSocket, Web界面, 依赖分析, 内核驱动, 场景测试, 多协议, 开发工具, 提示词优化, 搜索引擎查询, 故障注入, 日志审计, 模拟数据, 测试工具, 组件测试, 网络协议, 请求拦截