PowerMock是一个Mock Server的实现,它同时支持HTTP与gRPC协议接口的Mock,并提供了灵活的插件功能。
这个工具面向于前后端、测试等对有接口Mock需求的开发人员,也可以作为一个通用的Mock服务,部署在网关架构或API管理平台中,实现降级、接口Mock等功能。

  • PowerMock

    • 功能
    • 示例
      • 一、较为高级的用法

        • 1. 条件场景一
        • 2. 条件场景二
      • 二、从Hello World开始吧
        • 1. 先Mock一个HTTP接口
        • 2. 再mock一个gRPC接口
    • 安装
      • 通过Go安装
      • 开箱即用版本
      • 通过Makefile编译

项目地址

项目地址:PowerMock

功能

作为一个Mock Server,PowerMock具有以下的核心功能:

  1. 支持 HTTP协议gRPC协议 接口的Mock。
  2. 支持配置 Javascript 等脚本语言来动态生成响应。
  3. 支持对一个接口配置多种响应,并按照条件进行区分。
  4. 匹配条件支持多种运算符(AND/OR/>/</=等)。
  5. 支持返回静态数据以及 特定领域的随机数据
  6. 支持 插件 功能,可以通过编写插件实现其他匹配或Mock引擎。
  7. 同时提供HTTP与gRPC接口,可以动态对MockAPI进行 增删改查
  8. 开箱即用的Redis存储,并支持自由拓展其他存储引擎,比如MySQL、etcd。
  9. 同时支持 windows / darwin / linux 的 32 位 与 64 位。
  10. 语言无关,任何使用HTTP协议或gRPC协议的项目均可以使用本工具。

示例

一、较为高级的用法

本示例可以在 示例代码 找到对应资料
本示例必须使用v8版本的powermock,才能完整支持Javascript的功能

以下面这份配置为示例:

uniqueKey: "advanced_example"
path: "/examples.greeter.api.Greeter/Hello"
method: "POST"
cases:- condition:simple:items:- operandX: "$request.header.uid"operator: "<="operandY: "1000"response:simple:header:x-unit-id: "3"x-unit-region: "sh"trailer:x-api-version: "1.3.2"body: |{"timestamp": "1111", "message": "This message will only be returned when uid <= 1000", "amount": "{{ $mock.price }}"}- condition:simple:items:- operandX: "$request.header.uid"operator: ">"operandY: "1000"response:script:lang: "javascript"content: |(function(){function random(min, max){return parseInt(Math.random()*(max-min+1)+min,10);}return {code: 0,header: {"x-unit-id": (request.header["uid"] % 5).toString(),"x-unit-region": "bj",},trailer: {"x-api-version": "1.3.2",},body: {timestamp: Math.ceil(new Date().getTime() / 1000),message: "this message is generated by javascript, your uid is: " + request.header["uid"],amount: random(0, 5000),},}})()

这份配置定义了一个MockAPI,用于匹配所有路径为 /examples.greeter.api.Greeter/Hello,方法为 POST 的请求,它包含了两个场景,能够实现这样的效果:

1. 条件场景一

当请求 Header 中的 uid <= 1000 时:

  • Response Header 中写入:
x-unit-id: "3"
x-unit-region: "sh"
  • Response Trailer 中写入:
x-api-version: "1.3.2"
  • Response Body 中写入:
{"timestamp": "1111", "message": "This message will only be returned when uid <= 1000", "amount": "{{ $mock.price }}"}

其中的 {{ $mock.price }} 是魔法变量,用于返回一个随机的价格数据。最终,客户端收到的 Response Body 类似于:

{"timestamp": "1111","message": "This message will only be returned when uid <= 1000","amount": 7308.4
}

2. 条件场景二

当请求 Header 中的 uid > 1000 时,通过执行以下Javascript脚本返回响应:

(function(){function random(min, max){return parseInt(Math.random()*(max-min+1)+min,10);}return {code: 0,header: {"x-unit-id": (request.header["uid"] % 5).toString(),"x-unit-region": "bj",},trailer: {"x-api-version": "1.3.2",},body: {timestamp: Math.ceil(new Date().getTime() / 1000),message: "this message is generated by javascript, your uid is: " + request.header["uid"],amount: random(0, 5000),},}
})()

在这个脚本中,根据请求的 Header,以及一些内置或自定义函数来生成了响应的code、header、trailer与body。
最终客户端收到的响应体类似于:

{"timestamp": 1622093545,"message": "this message is generated by javascript, your uid is: 2233","amount": 314
}

它描述了一个相对复杂的场景,当然可能你的需求比较简单,实战的话,我们先从Hello World开始吧!

二、从Hello World开始吧

本示例可以在 示例代码 找到对应资料

首先,创建一个配置文件:

log:pretty: truelevel: debug
grpcmockserver:enable: trueaddress: 0.0.0.0:30002protomanager:protoimportpaths: [ ]protodir: ./apis
httpmockserver:enable: trueaddress: 0.0.0.0:30003
apimanager:grpcaddress: 0.0.0.0:30000httpaddress: 0.0.0.0:30001
pluginregistry: { }
plugin:simple: { }grpc: { }http: { }script: { }redis:enable: falseaddr: 127.0.0.1:6379password: ""db: 0prefix: /powermock/

将编译好的PowerMock与上面创建好的配置文件放到同一个目录中,像下面这样:

➜ ls -alh
total 45M
drwxrwxrwx 1 storyicon storyicon 4.0K May 27 14:18 .
drwxrwxrwx 1 storyicon storyicon 4.0K May 24 11:43 ..
-rwxrwxrwx 1 storyicon storyicon  546 May 27 14:16 config.yaml
-rwxrwxrwx 1 storyicon storyicon  45M May 27 14:18 powermock

然后执行

➜ ./powermock serve --config.file config.yaml

如果没有端口冲突的话,你应该已经可以看到服务运行起来了!

1. 先Mock一个HTTP接口

在上面的目录下,创建一个名为 apis.yaml 的文件:

uniqueKey: "hello_example_http"
path: "/hello"
method: "GET"
cases:- response:simple:header:x-unit-id: "3"x-unit-region: "sh"trailer:x-api-version: "1.3.2"body: |hello world!

然后运行:

➜ ./powermock load --address=127.0.0.1:30000 apis.yaml
2:32PM INF start to load file component=main file=load.go:59
2:32PM INF mock apis loaded from file component=main count=1 file=load.go:64
2:32PM INF start to save api component=main file=load.go:76 host= method=GET path=/hello uniqueKey=hello
2:32PM INF succeed! component=main file=load.go:89

这样,我们描述的MockAPI就创建起来了。

通过 curl 或者你的浏览器请求 http://127.0.0.1:30003/hello,可以看到返回给我们 hello world 了!

➜ curl http://127.0.0.1:30003/hello -i
HTTP/1.1 200 OK
Content-Type: application/json
X-Unit-Id: 3
X-Unit-Region: sh
Date: Thu, 27 May 2021 06:36:28 GMT
Content-Length: 12hello world!

2. 再mock一个gRPC接口

在上面的目录中,创建一个 apis 目录,使整个目录结构像下面这样:

➜  ls -alh
total 45M
drwxrwxrwx 1 storyicon storyicon 4.0K May 27 14:42 .
drwxrwxrwx 1 storyicon storyicon 4.0K May 27 14:37 ..
drwxrwxrwx 1 storyicon storyicon 4.0K May 27 14:23 apis
-rwxrwxrwx 1 storyicon storyicon 1.8K May 27 14:32 apis.yaml
-rwxrwxrwx 1 storyicon storyicon  546 May 27 14:16 config.yaml
-rwxrwxrwx 1 storyicon storyicon  45M May 27 14:18 powermock

在 apis 目录中创建我们的 greeter.proto:

syntax = "proto3";package examples.greeter.api;
option go_package = "github.com/bilibili-base/powermock/examples/helloWorld/apis;apis";service Greeter {rpc Hello(HelloRequest) returns (HelloResponse);
}message HelloRequest {string message = 2;
}message HelloResponse {string message = 2;
}

现在整个目录结构像这样:

.
├── apis
│   └── greeter.proto
├── apis.yaml
├── config.yaml
└── powermock

重新运行我们的 powermock 来加载我们新写的proto文件:

➜ ./powermock serve --config.file config.yaml
2:55PM INF starting load proto from: ./apis component=main.gRPCMockServer.protoManager file=service.go:102
2:55PM INF api loaded component=main.gRPCMockServer.protoManager file=service.go:131 name=/examples.greeter.api.Greeter/Hello

在启动日志中可以看到我们新创建的 proto 文件已经被加载到 PowerMock 中了。

将我们的 apis.yaml 文件修改成下面的内容:

uniqueKey: "hello_example_http"
path: "/hello"
method: "GET"
cases:- response:simple:header:x-unit-id: "3"x-unit-region: "sh"trailer:x-api-version: "1.3.2"body: |hello world!---uniqueKey: "hello_example_gRPC"
path: "/examples.greeter.api.Greeter/Hello"
method: "POST"
cases:- response:simple:header:x-unit-id: "3"x-unit-region: "sh"trailer:x-api-version: "1.3.2"body: |{"message": "hello world!"}

可以看到,里面添加了一个名为 “hello_example_gRPC” 的 MockAPI,我们通过下面的命令装载它:

➜ powermock load --address=127.0.0.1:30000  apis.yaml
3:06PM INF start to load file component=main file=load.go:59
3:06PM INF mock apis loaded from file component=main count=2 file=load.go:64
3:06PM INF start to save api component=main file=load.go:76 host= method=GET path=/hello uniqueKey=hello_example_http
3: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
3:06PM INF succeed! component=main file=load.go:89

这样,我们的MockAPI就被添加到PowerMock中了。

如果你的环境中有BloomRPC之类的工具的话,可以先通过BloomRPC加载 greeter.proto,然后调用 127.0.0.1:30002

可以看到,调用成功返回了 “hello world”。
如果使用编程语言进行调用的话,以 golang 为例,通过下面的代码调用 PowerMock:

func main() {fmt.Println("starting call mock server")conn, err := grpc.Dial("127.0.0.1:30002", grpc.WithInsecure())if err != nil {panic(err)}client := apis.NewGreeterClient(conn)var header, trailer metadata.MDstartTime := time.Now()resp, err := client.Hello(context.TODO(), &apis.HelloRequest{Message: "hi",}, grpc.Header(&header), grpc.Trailer(&trailer))if err != nil {panic(err)}fmt.Printf("[elapsed] %d ms \r\n", time.Since(startTime).Milliseconds())fmt.Printf("[headers] %+v \r\n", header)fmt.Printf("[trailer] %+v \r\n", trailer)fmt.Printf("[response] %+v \r\n", resp.String())
}

日志输出是这样的:

starting call mock server
[elapsed] 2 ms
[headers] map[content-type:[application/grpc] x-unit-id:[3] x-unit-region:[sh]]
[trailer] map[x-api-version:[1.3.2]]
[response] message:"This message will only be returned when uid <= 1000"

可以看到,我们的接口被成功Mock出来了!

安装

通过Go安装

安装普通版本,无Javascript支持:

go install github.com/bilibili-base/powermock/cmd/powermock

安装V8版本,支持Javascript:

go install github.com/bilibili-base/powermock/cmd/powermock-v8

开箱即用版本

如果你没有定制插件的需求,开箱即用版本 非常适合你。

通过Makefile编译

如果你是 linux/darwin/wsl 的用户,推荐使用 makefile 来进行安装:

➜ git clone https://github.com/bilibili-base/powermock
➜ cd powermock
➜ make build_linux_v8
➜ make build_linux
➜ make build_darwin
➜ make build_windows

当然也可以直接进行编译:

➜ cd ./cmd/powermock
➜ go install
➜ go build .

gRPC Mock Server相关推荐

  1. 1分钟搭建极简mock server

    摘自博客园:https://www.cnblogs.com/mikasama/p/9838480.html 1.无聊的背景.起源: 如今的业务系统越来越复杂庞大,各个功能直接的调用也是多如牛毛,但如果 ...

  2. 如何优雅的使用Mock Server

    事出有因 昨天跟同事讨论我们在用的rap2(一个集接口编写和mock server的开源项目)和刚上线了一个easy-mock的server,到底哪个好用. 我们主要讨论的点有个两个: 接口的一致性. ...

  3. python接口测试实战_Python接口测试实战5(下) - RESTful、Web Service及Mock Server

    课程目录 更多学习资料请加添加作者微信:superz-han获取 本节内容 REST及RESTful API Web Service XML解析 Mock Server REST及RESTful AP ...

  4. java mockserver搭建_搭建Mock Server

    1.为什么要搭建mock-server? 为了更好的分工合作,让前端能在不依赖后端环境的情况下进行开发,其中一种手段就是为前端开发者提供一个 web 容器,这个本地环境就是 mock-server. ...

  5. SAP UI5 应用开发教程之六十三 - 基于 OData V4 的本地 Mock Server 实现的深入介绍试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

  6. SAP UI5 应用开发教程之六十三 - 基于 OData V4 的本地 Mock Server 实现的深入介绍

    学习本步骤之前,请确保你已经复习了步骤 26 和 步骤 62 的知识: SAP UI5 应用开发教程之二十六 - OData 服务配合 Mock 服务器的使用步骤详解 SAP UI5 应用开发教程之六 ...

  7. 如何以 mock server 的方式本地启动 SAP UI5 应用,使它不连接服务器端 OData 服务

    我们在做 SAP UI5 开发时,在视图逻辑没有开发完毕时,往往不希望连接服务器端的 OData 服务进行联调,而仅仅连接本地端的测试数据. 本文介绍如果启动本地 mock server,将 SAP ...

  8. 搭建Mock Server

    搭建Mock Server 1.为什么要搭建mock-server? 为了更好的分工合作,让前端能在不依赖后端环境的情况下进行开发,其中一种手段就是为前端开发者提供一个 web 容器,这个本地环境就是 ...

  9. pythonflaskmock数据_Flask实现简单Mock Server

    Mock Server充当的角色: Mock server在实际项目中的意义就相当于数据库.将我想要的数据返回给我就行,我并不关心你怎么逻辑处理的. 一般的应用程序请求方式是GET和POST. Fla ...

  10. 基于django rest framework的mock server实践

    网上找了一下mock server的实现,发现python的基本都是基于flask来实现的,因最近在学django,就尝试用drf实现了下: A brief introduction of sui_m ...

最新文章

  1. 深度神经网络混合精度训练
  2. 暑期集训1:C++STL 练习题C:HDU-1263
  3. 【每日scrum】NO.5
  4. Tomcat7.0+的JNDI问题
  5. cesium 设置地球默认区域为中国 一键返回默认区域
  6. [Unity] GameFramework 学习记录 3
  7. android 中 DOM解析xml
  8. 超简单!基于Python搭建个人“云盘”
  9. 转:Loadrunner打开https报错“Internet…
  10. 树莓派运行java_【树莓派】用树莓派4可以流畅运行java版minecraft?
  11. D3D自定义的设备丢失对象
  12. Mysql SQLyog 使用详解
  13. 互联网30年,泡沫如梦,一个个泡沫和风口过后,会是什么样的结局
  14. Linux 常用系统故障(修复MBR扇区故障、修复GRUB引导故障、遗忘root用户密码、修复文件系统、磁盘配额等)
  15. 1.国民技术N32G45X例程之-串口打印
  16. 一款懒人必备的Python爬虫神器
  17. hdu5804(BestCoder Round #86 A)
  18. 传感器为什么在低量程偏差大_高精度、超低量程的压力传感器概述
  19. GF(2^8)的加法与乘法计算
  20. Wilcoxon rank-sum 和 signed-rank

热门文章

  1. C语言大作业--小型工资管理系统
  2. 神策分析 iOS SDK 代码埋点解析 | 数据采集
  3. mysql 中国省份城市数据库表
  4. Android实现连线题效果
  5. python保存到txt_python保存成文本文件
  6. 开源阅读书源_免费开源网络文学阅读器(万本小说免费阅读)
  7. a59s刷机包卡刷 oppo_OPPO A59s 5.1 ROM刷机包 ColorOS 精简卡刷包 ROOT权限
  8. USB接口IC读写器oem软件_AB密码完整解决方案/读写卡测试程序及源代码/c++builder源代码(2)
  9. ICD3 - Cannot connect to USB device. Unrecognized endpoint.
  10. 固态硬盘用软件测试掉速严重,SSD固态硬盘掉速怎么办?手动执行TRIM指令缓解固态硬盘掉速方法...