闽公网安备 35020302035485号


$ go get github.com/bilibili-base/powermock/cmd/powermock $ go get github.com/bilibili-base/powermock/cmd/powermock-v8 // 支持 javascript 的 server配置
log:
pretty: true
level: debug
grpcmockserver:
enable: true
address: 0.0.0.0:30002
protomanager:
protoimportpaths: [ ]
protodir: ./apis
httpmockserver:
enable: true
address: 0.0.0.0:30003
apimanager:
grpcaddress: 0.0.0.0:30000
httpaddress: 0.0.0.0:30001
pluginregistry: { }
plugin:
simple: { }
grpc: { }
http: { }
script: { }
redis:
enable: false
addr: 127.0.0.1:6379
password: ""
db: 0
prefix: /powermock/
如果已经了解前面的架构,这里的配置就比较容易理解了。plugin 插件配置,插件的管理配置,这里吐槽一下, powermock 将所有类别的插件在一个 plugin 配置项下,类别区分不明晰,如果增加二级目录,如 mock、match、storage,配置会更加易懂;
syntax = "proto3";
package examples.hello.api;
option go_package = "github.com/poloxue/mock/examples/greeter";
service Greeter {
rpc Hello(HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string message = 2;
}
message HelloResponse {
string message = 2;
}
在 greeter 目录下执行使用 protoc 命令编译 proto 文件,如下:$ protoc -I. --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. ./apis/*.proto编译生成文件包括 greeter/apis/greeter.pb.go 和 greeter/apis/greeter_grpc.pb.go。
log:
pretty: true
level: debug
grpcmockserver:
enable: true
address: 0.0.0.0:30002
protomanager:
protoimportpaths: []
protodir: ./apis
httpmockserver:
enable: true
address: 0.0.0.0:30003
apimanager:
grpcaddress: 0.0.0.0:30000
httpaddress: 0.0.0.0:30001
pluginregistry: { }
plugin:
simple:
enable: true
配置的具体含义参考前面的介绍,主要的是启用的 plugin 是 simple,最简单的内存版本。执行如下命令启动服务:$ powermock serve --config.file config.yaml 9:18PM INF * start to create pluginRegistry component=main file=setup.go:40 9:18PM INF * start to create apiManager component=main file=setup.go:46 9:18PM INF * start to create httpMockServer component=main file=setup.go:63 ... 9:18PM INF starting service component=main.gRPCMockServer.gRPC file=service.go:29 9:18PM INF starting service component=main.apiManager.http file=service.go:29 9:18PM INF starting service component=main.httpMockServer file=service.go:29输出日志,成功启动服务。
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!"}
上述不仅设置了响应的 body,还设置了 x-unit-id 等 header 和 grpc trailer 信息。# 堆代码 duidaima.com $ powermock load --address=127.0.0.1:30000 apis.yaml加载完成后,我们可以直接通过 grpcurl 命令验证下 Mock 的结果是否是我们想要的。
$ protoc --proto_path=. --descriptor_set_out=greeter.protoset --include_imports apis/*.proto
$ grpcurl -plaintext -protoset greeter.protoset 127.0.0.1:30002 examples.greeter.api.Greeter/Hello
{
"message": "hello world!"
}
通过 powermock 的 load 将 apis 配置加载到 mock server 的内存中,但这种方式,如果一旦我们重启了 mock server,先前定义的配置就会失效。有没有持久化的方案呢?有,就是接下来要介绍的 redis 方案。redis: enable: true addr: 127.0.0.1:6379 password: "" db: 0 prefix: /mockserver/重启 Mock 服务之后,再次 load apis 配置信息。
127.0.0.1:6379> keys * 1) "/mockserver/hello_example_gRPC" 2) "/mockserver/__REVISION__"通过 redis 持久化存储的 Mock 规则的好处不言而喻。不断补充依赖服务在正式场景下的规则,逐步完成一个与真实场景几近相同的 Mock Server,无论是开发人员效率,还是自动化测试的场景覆盖都有极大的提升。
uniqueKey: "hello_example_http"
path: "/hello"
method: "GET"
cases:
- response:
simple:
header:
x-unit-id: "3"
x-unit-region: "sh"
trailer:
x-api-vesion: "1.3.2"
body:
hello world!
通过 curl 命令测试下 mock 结果,如下:$ curl -v http://localhost:30003/hello * Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 30003 (#0) > GET /hello HTTP/1.1 > Host: localhost:30003 > User-Agent: curl/7.64.1 > Accept: */* > < HTTP/1.1 200 OK < Content-Type: application/json < X-Unit-Id: 3 < X-Unit-Region: sh < Date: Sun, 11 Jul 2021 08:06:57 GMT < Content-Length: 12 < * Connection #0 to host localhost left intact hello world!* Closing connection 0至此,一个 HTTP 接口的 Mock 已经完成。
前置准备
还是以一个真实的场景为例吧,一个简单的用户服务的 proto 接口定义。
syntax = "proto3";
package examples.user.api;
option go_package = "github.com/poloxue/mock/examples/user/apis";
service User {
rpc Register(GetUserRequest) returns(GetUserResponse);
rpc SetUserDetail(SetUserDetailRequest) returns(SetUserDetailRequest);
rpc GetUser(GetUserRequest) returns(GetUserResponse);
}
message RegisterRequest {
string mobile = 1;
string password = 2;
}
message RegisterResponse {
int32 status = 1;
}
message SetUserDetailRequest {
int64 id = 1;
string mobile = 2;
string username = 3;
string email = 4;
}
message GetUserRequest {
int64 id = 1;
string mobile = 2;
}
message GetUserResponse {
int64 id = 1;
string mobile = 2;
string username = 3;
string email = 4;
}
共三个接口,分别是用户注册、设置详情以及获取用户信息。我们按 快速开始 中的步骤把 proto 的 go 文件编译,配置等准备完成。{
"id": 1000,
"mobile": "15300000001",
"username": "poloxue",
"email": "[poloxue123@gmail.com](mailto:poloxue123@gmail.com)"
}
配置 Mock 规则如下:uniqueKey: "get_user_gRPC"
path: "/examples.user.api.User/GetUser"
method: "POST"
cases:
- condition:
simple:
items:
- operandX: "$request.body.id"
operator: "=="
operandY: "1000"
response:
simple:
body: |
{"id": 1000, "mobile": "15300000001", "username": "poloxue", "email": "poloxue123@gmail.com"}
将配置加载到 Mock Server 中,通过 grpcurl 请求数据,将得到如下结果:$ grpcurl -d '{"id": 1000}' -plaintext -protoset user.protoset 127.0.0.1:30002 examples.user.api.User/GetUser
{
"id": "1000",
"mobile": "15300000001",
"username": "poloxue",
"email": "poloxue123@gmail.com"
}
上述通过 condition 的判断,如果 $request.body.id 是 1000,则返回特定的用户数据。- condition:
simple:
items:
- operandX: "$request.body.id"
operator: "<"
operandY: "500"
response:
script:
lang: "javascript"
content: |
(function () {
function pad(num, size) {
num = num.toString();
while (num.length < size) num = "0" + num;
return num;
}
return {
code: 0,
body: {
id: request.body.id,
username: 'username' + request.body.id,
mobile: '1530000' + pad(request.body.id, 4),
},
}
})()
使用 powermock load 命令加载新的配置到 server 中。至此,如果我们使用 grpcurl 访问这个服务,得到的信息如下:$ grpcurl -d '{"id": 100}' -plaintext -protoset user.protoset 127.0.0.1:30002 examples.user.api.User/GetUser
ERROR:
Code: Internal
Message: plugin(grpc): failed to unmarshal: EOF
因为,如果希望通过脚本生成 mock 数据,要将 powermock 替换为 powermock-v8 命令才可执行javascript 脚本。$ grpcurl -d '{"id": 1}' -plaintext -protoset user.protoset 127.0.0.1:30002 examples.user.api.User/GetUser
{
"id": "1",
"mobile": "15300000001",
"username": "username1"
}
$ grpcurl -d '{"id": 100}' -plaintext -protoset user.protoset 127.0.0.1:30002 examples.user.api.User/GetUser
{
"id": "100",
"mobile": "15300000100",
"username": "username100"
}
一个批量 Mock 用户数据的规则就写好了。