{"id":37142303,"url":"https://github.com/bilibili-base/powermock","last_synced_at":"2026-01-14T16:42:12.606Z","repository":{"id":39224705,"uuid":"370218707","full_name":"bilibili-base/powermock","owner":"bilibili-base","description":"Support for gRPC/HTTP protocol, feature-rich Mock Server implementation.","archived":false,"fork":false,"pushed_at":"2024-04-15T04:05:05.000Z","size":250,"stargazers_count":105,"open_issues_count":5,"forks_count":24,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-14T04:32:50.066Z","etag":null,"topics":["bilibili","grpc","http","mock","mock-server","powermock"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bilibili-base.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-24T03:42:04.000Z","updated_at":"2025-02-07T12:22:22.000Z","dependencies_parsed_at":"2025-03-14T07:15:11.870Z","dependency_job_id":null,"html_url":"https://github.com/bilibili-base/powermock","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/bilibili-base/powermock","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bilibili-base%2Fpowermock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bilibili-base%2Fpowermock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bilibili-base%2Fpowermock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bilibili-base%2Fpowermock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bilibili-base","download_url":"https://codeload.github.com/bilibili-base/powermock/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bilibili-base%2Fpowermock/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28426186,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T16:38:47.836Z","status":"ssl_error","status_checked_at":"2026-01-14T16:34:59.695Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bilibili","grpc","http","mock","mock-server","powermock"],"created_at":"2026-01-14T16:42:11.985Z","updated_at":"2026-01-14T16:42:12.600Z","avatar_url":"https://github.com/bilibili-base.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PowerMock \n[![Go Report Card](https://goreportcard.com/badge/github.com/bilibili-base/powermock?t=1)](https://goreportcard.com/report/github.com/bilibili-base/powermock) ![TotalLine](https://img.shields.io/tokei/lines/github/bilibili-base/powermock?color=77%2C199%2C31) ![last-commit](https://img.shields.io/github/last-commit/bilibili-base/powermock) [![GoDoc](https://godoc.org/github.com/bilibili-base/powermock?status.svg)](https://godoc.org/github.com/bilibili-base/powermock) \n\n**中文** | [English](README_EN.md)\n\n![powermock](https://socialify.git.ci/bilibili-base/powermock/image?language=1\u0026owner=1\u0026pattern=Diagonal%20Stripes\u0026theme=Dark)\n\nPowerMock是一个Mock Server的实现，它同时支持HTTP与gRPC协议接口的Mock，并提供了灵活的插件功能。\n这个工具面向于前后端、测试等对有接口Mock需求的开发人员，也可以作为一个通用的Mock服务，部署在网关架构或API管理平台中，实现降级、接口Mock等功能。\n\n- [PowerMock](#powermock)\n  - [功能](#功能)\n  - [示例](#示例)\n    - [一、较为高级的用法](#一较为高级的用法)\n      - [0 TIPS](#0-tips)\n      - [1. 条件场景一](#1-条件场景一)\n      - [2. 条件场景二](#2-条件场景二)\n    - [二、从Hello World开始吧](#二从hello-world开始吧)\n      - [1. 先Mock一个HTTP接口](#1-先mock一个http接口)\n      - [2. 再mock一个gRPC接口](#2-再mock一个grpc接口)\n  - [安装](#安装)\n    - [通过Go安装](#通过go安装)\n    - [开箱即用版本](#开箱即用版本)\n    - [通过Makefile编译](#通过makefile编译)\n\n## 功能\n\n作为一个Mock Server，PowerMock具有以下的核心功能：\n1. 支持 **HTTP协议** 与 **gRPC协议** 接口的Mock。\n2. 支持配置 **Javascript** 等脚本语言来动态生成响应。\n3. 支持对一个接口配置多种响应，并**按照条件**进行区分。\n4. 匹配条件支持**多种运算符**(AND/OR/\u003e/\u003c/=等)。\n4. 支持返回静态数据以及 **特定领域的随机数据**。\n5. 支持 **插件** 功能，可以通过编写插件实现其他匹配或Mock引擎。\n6. 同时提供HTTP与gRPC接口，可以动态对MockAPI进行 **增删改查** 。\n7. 开箱即用的Redis存储，并支持**自由拓展其他存储引擎**，比如MySQL、etcd。\n8. 同时支持 windows / darwin / linux 的 32 位 与 64 位。\n9. 语言无关，任何使用HTTP协议或gRPC协议的项目均可以使用本工具。\n\n## 示例\n\n### 一、较为高级的用法\n\n\u003e 本示例可以在 [示例代码](./examples/advanced) 找到对应资料\n\u003e 本示例必须使用v8版本的powermock，才能完整支持Javascript的功能\n\n以下面这份配置为示例：\n\n```yaml\nuniqueKey: \"advanced_example\"\npath: \"/examples.greeter.api.Greeter/Hello\"\nmethod: \"POST\"\ncases:\n  - condition:\n      simple:\n        items:\n          - operandX: \"$request.header.uid\"\n            operator: \"\u003c=\"\n            operandY: \"1000\"\n            # 反转判断结果\n            opposite: true\n    response:\n      simple:\n        header:\n          x-unit-id: \"3\"\n          x-unit-region: \"sh\"\n        trailer:\n          x-api-version: \"1.3.2\"\n        body: |\n          {\"timestamp\": \"1111\", \"message\": \"This message will only be returned when uid \u003c= 1000\", \"amount\": \"{{ $mock.price }}\"}\n  - condition:\n      simple:\n        items:\n          - operandX: \"$request.header.uid\"\n            operator: \"\u003e\"\n            operandY: \"1000\"\n    response:\n      script:\n        lang: \"javascript\"\n        content: |\n          (function(){\n              function random(min, max){\n                  return parseInt(Math.random()*(max-min+1)+min,10);\n              }\n              return {\n                  code: 0,\n                  header: {\n                      \"x-unit-id\": (request.header[\"uid\"] % 5).toString(),\n                      \"x-unit-region\": \"bj\",\n                  },\n                  trailer: {\n                      \"x-api-version\": \"1.3.2\",\n                  },\n                  body: {\n                      timestamp: Math.ceil(new Date().getTime() / 1000),\n                      message: \"this message is generated by javascript, your uid is: \" + request.header[\"uid\"],\n                      amount: random(0, 5000),\n                  },\n              }\n          })()\n```\n#### 0 TIPS\ncondition可用字段说明\n\n| 字段 | 类型 | 备注 |\n| -- | -- | -- |\n| items | []Item | 用来运算的数据项 |\n| useOrAmongItems | bool |  运算数据项间的逻辑关系，or/and|\n\nItem\n| 字段 | 类型 | 备注 |\n| -- | -- | -- |\n| operandX | string | 输入值 |\n| operandY | string | 运算值 |\n| opposite | bool | 运算结果反转，相当加了个非门 |\n| operator | string | 运算符，=,\\==,===、!=,\u003e,\u003e=,\u003c,\u003c=,regex,in等 |\n\n这份配置定义了一个`MockAPI`，用于匹配所有路径为 `/examples.greeter.api.Greeter/Hello`，方法为 `POST` 的请求，它包含了两个场景，能够实现这样的效果：\n\n#### 1. 条件场景一\n当请求 Header 中的 `uid \u003c= 1000` 时：\n* Response Header 中写入:\n```\nx-unit-id: \"3\"\nx-unit-region: \"sh\"\n```\n* Response Trailer 中写入:\n```\nx-api-version: \"1.3.2\"\n```\n* Response Body 中写入:\n```\n{\"timestamp\": \"1111\", \"message\": \"This message will only be returned when uid \u003c= 1000\", \"amount\": \"{{ $mock.price }}\"}\n```\n其中的 `{{ $mock.price }}` 是魔法变量，用于返回一个随机的价格数据。最终，客户端收到的 `Response Body` 类似于：\n```\n{\n\t\"timestamp\": \"1111\",\n\t\"message\": \"This message will only be returned when uid \u003c= 1000\",\n\t\"amount\": 7308.4\n}\n```\n\n#### 2. 条件场景二\n当请求 Header 中的 `uid \u003e 1000` 时，通过执行以下Javascript脚本返回响应：\n```\n(function(){\n    function random(min, max){\n        return parseInt(Math.random()*(max-min+1)+min,10);\n    }\n    return {\n        code: 0,\n        header: {\n            \"x-unit-id\": (request.header[\"uid\"] % 5).toString(),\n            \"x-unit-region\": \"bj\",\n        },\n        trailer: {\n            \"x-api-version\": \"1.3.2\",\n        },\n        body: {\n            timestamp: Math.ceil(new Date().getTime() / 1000),\n            message: \"this message is generated by javascript, your uid is: \" + request.header[\"uid\"],\n            amount: random(0, 5000),\n        },\n    }\n})()\n```\n在这个脚本中，根据请求的 Header，以及一些内置或自定义函数来生成了响应的code、header、trailer与body。\n最终客户端收到的响应体类似于：\n```\n{\n\t\"timestamp\": 1622093545,\n\t\"message\": \"this message is generated by javascript, your uid is: 2233\",\n\t\"amount\": 314\n}\n```\n\n它描述了一个相对复杂的场景，当然可能你的需求比较简单，实战的话，我们先从Hello World开始吧！\n\n\n### 二、从Hello World开始吧\n\n\u003e 本示例可以在 [示例代码](./examples/helloworld) 找到对应资料\n\n首先，创建一个配置文件：\n```\nlog:\n    pretty: true\n    level: debug\ngrpcmockserver:\n    enable: true\n    address: 0.0.0.0:30002\n    protomanager:\n        protoimportpaths: [ ]\n        protodir: ./apis\nhttpmockserver:\n    enable: true\n    address: 0.0.0.0:30003\napimanager:\n    grpcaddress: 0.0.0.0:30000\n    httpaddress: 0.0.0.0:30001\npluginregistry: { }\nplugin:\n    simple: { }\n    grpc: { }\n    http: { }\n    script: { }\n    redis:\n        enable: false\n        addr: 127.0.0.1:6379\n        password: \"\"\n        db: 0\n        prefix: /powermock/\n```\n\n将编译好的PowerMock与上面创建好的配置文件放到同一个目录中，像下面这样：\n```\n➜ ls -alh\ntotal 45M\ndrwxrwxrwx 1 storyicon storyicon 4.0K May 27 14:18 .\ndrwxrwxrwx 1 storyicon storyicon 4.0K May 24 11:43 ..\n-rwxrwxrwx 1 storyicon storyicon  546 May 27 14:16 config.yaml\n-rwxrwxrwx 1 storyicon storyicon  45M May 27 14:18 powermock\n```\n\n然后执行\n```\n➜ ./powermock serve --config.file config.yaml\n```\n如果没有端口冲突的话，你应该已经可以看到服务运行起来了!\n\n#### 1. 先Mock一个HTTP接口\n\n在上面的目录下，创建一个名为 apis.yaml 的文件:\n```yaml\nuniqueKey: \"hello_example_http\"\npath: \"/hello\"\nmethod: \"GET\"\ncases:\n    - response:\n          simple:\n              header:\n                  x-unit-id: \"3\"\n                  x-unit-region: \"sh\"\n              trailer:\n                  x-api-version: \"1.3.2\"\n              body: |\n                  hello world!\n```\n\n然后运行：\n```\n➜ ./powermock load --address=127.0.0.1:30000 apis.yaml\n2:32PM INF start to load file component=main file=load.go:59\n2:32PM INF mock apis loaded from file component=main count=1 file=load.go:64\n2:32PM INF start to save api component=main file=load.go:76 host= method=GET path=/hello uniqueKey=hello\n2:32PM INF succeed! component=main file=load.go:89\n```\n\n这样，我们描述的MockAPI就创建起来了。\n\n通过 `curl` 或者你的浏览器请求 `http://127.0.0.1:30003/hello`，可以看到返回给我们 hello world 了！\n```\n➜ curl http://127.0.0.1:30003/hello -i\nHTTP/1.1 200 OK\nContent-Type: application/json\nX-Unit-Id: 3\nX-Unit-Region: sh\nDate: Thu, 27 May 2021 06:36:28 GMT\nContent-Length: 12\n\nhello world!\n\n```\n\n#### 2. 再mock一个gRPC接口\n\n在上面的目录中，创建一个 apis 目录，使整个目录结构像下面这样：\n```\n➜  ls -alh\ntotal 45M\ndrwxrwxrwx 1 storyicon storyicon 4.0K May 27 14:42 .\ndrwxrwxrwx 1 storyicon storyicon 4.0K May 27 14:37 ..\ndrwxrwxrwx 1 storyicon storyicon 4.0K May 27 14:23 apis\n-rwxrwxrwx 1 storyicon storyicon 1.8K May 27 14:32 apis.yaml\n-rwxrwxrwx 1 storyicon storyicon  546 May 27 14:16 config.yaml\n-rwxrwxrwx 1 storyicon storyicon  45M May 27 14:18 powermock\n```\n\n在 apis 目录中创建我们的 greeter.proto：\n\n```\nsyntax = \"proto3\";\n\npackage examples.greeter.api;\noption go_package = \"github.com/bilibili-base/powermock/examples/helloWorld/apis;apis\";\n\nservice Greeter {\n    rpc Hello(HelloRequest) returns (HelloResponse);\n}\n\nmessage HelloRequest {\n    string message = 2;\n}\n\nmessage HelloResponse {\n    string message = 2;\n}\n```\n\n现在整个目录结构像这样：\n```\n.\n├── apis\n│   └── greeter.proto\n├── apis.yaml\n├── config.yaml\n└── powermock\n```\n\n重新运行我们的 `powermock` 来加载我们新写的proto文件：\n```\n➜ ./powermock serve --config.file config.yaml\n2:55PM INF starting load proto from: ./apis component=main.gRPCMockServer.protoManager file=service.go:102\n2:55PM INF api loaded component=main.gRPCMockServer.protoManager file=service.go:131 name=/examples.greeter.api.Greeter/Hello\n```\n在启动日志中可以看到我们新创建的 proto 文件已经被加载到 PowerMock 中了。\n\n将我们的 apis.yaml 文件修改成下面的内容：\n```\nuniqueKey: \"hello_example_http\"\npath: \"/hello\"\nmethod: \"GET\"\ncases:\n    - response:\n          simple:\n              header:\n                  x-unit-id: \"3\"\n                  x-unit-region: \"sh\"\n              trailer:\n                  x-api-version: \"1.3.2\"\n              body: |\n                  hello world!\n\n---\n\nuniqueKey: \"hello_example_gRPC\"\npath: \"/examples.greeter.api.Greeter/Hello\"\nmethod: \"POST\"\ncases:\n    - response:\n          simple:\n              header:\n                  x-unit-id: \"3\"\n                  x-unit-region: \"sh\"\n              trailer:\n                  x-api-version: \"1.3.2\"\n              body: |\n                  {\"message\": \"hello world!\"}\n```\n可以看到，里面添加了一个名为 \"hello_example_gRPC\" 的 MockAPI，我们通过下面的命令装载它：\n```\n➜ powermock load --address=127.0.0.1:30000  apis.yaml\n3:06PM INF start to load file component=main file=load.go:59\n3:06PM INF mock apis loaded from file component=main count=2 file=load.go:64\n3:06PM INF start to save api component=main file=load.go:76 host= method=GET path=/hello uniqueKey=hello_example_http\n3:06PM INF start to save api component=main file=load.go:76 host= method=POST path=/examples.greeter.api.Greeter/Hello uniqueKey=hello_example_gRPC\n3:06PM INF succeed! component=main file=load.go:89\n```\n这样，我们的MockAPI就被添加到PowerMock中了。\n\n如果你的环境中有BloomRPC之类的工具的话，可以先通过BloomRPC加载 greeter.proto，然后调用 `127.0.0.1:30002`：\n\n![hello_world_bloomrpc](./docs/images/hello_world_bloomrpc.png)\n\n可以看到，调用成功返回了 \"hello world\"。\n如果使用编程语言进行调用的话，以 golang 为例，通过下面的代码调用 `PowerMock`:\n```go\nfunc main() {\n\tfmt.Println(\"starting call mock server\")\n\tconn, err := grpc.Dial(\"127.0.0.1:30002\", grpc.WithInsecure())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tclient := apis.NewGreeterClient(conn)\n\n\tvar header, trailer metadata.MD\n\tstartTime := time.Now()\n\tresp, err := client.Hello(context.TODO(), \u0026apis.HelloRequest{\n\t\tMessage: \"hi\",\n\t}, grpc.Header(\u0026header), grpc.Trailer(\u0026trailer))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"[elapsed] %d ms \\r\\n\", time.Since(startTime).Milliseconds())\n\tfmt.Printf(\"[headers] %+v \\r\\n\", header)\n\tfmt.Printf(\"[trailer] %+v \\r\\n\", trailer)\n\tfmt.Printf(\"[response] %+v \\r\\n\", resp.String())\n}\n```\n日志输出是这样的：\n```\nstarting call mock server\n[elapsed] 2 ms\n[headers] map[content-type:[application/grpc] x-unit-id:[3] x-unit-region:[sh]]\n[trailer] map[x-api-version:[1.3.2]]\n[response] message:\"This message will only be returned when uid \u003c= 1000\"\n```\n\n可以看到，我们的接口被成功Mock出来了！\n\n\n## 安装\n\n### 通过Go安装\n\n安装普通版本，无Javascript支持：\n```\ngo install github.com/bilibili-base/powermock/cmd/powermock@latest\n```\n\n安装V8版本，支持Javascript：\n```\ngo install github.com/bilibili-base/powermock/cmd/powermock-v8@latest\n```\n\n### 开箱即用版本\n\n如果你没有定制插件的需求，[开箱即用版本](https://github.com/bilibili-base/powermock/releases) 非常适合你。\n\n### 通过Makefile编译\n\n如果你是 `linux/darwin/wsl` 的用户，推荐使用 makefile 来进行安装：\n```\n➜ git clone https://github.com/bilibili-base/powermock\n➜ cd powermock\n➜ make build_linux_v8\n➜ make build_linux\n➜ make build_darwin\n➜ make build_windows\n```\n\n当然也可以直接进行编译：\n\n```\n➜ cd ./cmd/powermock\n➜ go install\n➜ go build .\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbilibili-base%2Fpowermock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbilibili-base%2Fpowermock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbilibili-base%2Fpowermock/lists"}