PowerMock — это реализация Mock Server, которая поддерживает интерфейсы протоколов HTTP и gRPC и предоставляет гибкие функции подключаемых модулей. Этот инструмент предназначен для разработчиков, у которых есть требования к имитации интерфейса для внешнего интерфейса, серверной части, тестирования и т. д. Его также можно развернуть в качестве общей службы имитации в архитектуре шлюза или платформе управления API для реализации таких функций, как переход на более раннюю версию и интерфейс. насмешливый.
адрес проекта
Функции
В качестве фиктивного сервера PowerMock имеет следующие основные функции:
- служба поддержкиHTTP-протоколипротокол gRPCМакет интерфейса.
- Поддержка конфигурацииJavascriptи другие языки сценариев для динамической генерации ответов.
- Поддерживает настройку нескольких ответов на интерфейс ипо условиюдифференцировать.
- Поддержка условий совпадениянесколько операторов(И/ИЛИ/>/= и т. д.).
- Поддерживает возврат статических данных, а такжеполевые случайные данные.
- служба поддержкиплагинФункции, другие механизмы сопоставления или Mock-движки могут быть реализованы путем написания плагинов.
- При этом предоставляются интерфейсы HTTP и gRPC, а MockAPI может быть реализован динамически.CRUD.
- Готовое хранилище Redis и поддержкаСвободно расширяйте другие механизмы хранения, такие как MySQL и т. д.
- Поддерживаются как 32-битные, так и 64-битные windows/darwin/linux.
- Независимо от языка, любой проект, использующий протокол HTTP или протокол gRPC, может использовать этот инструмент.
Пример
Более продвинутое использование
Этот пример можно найти вобразец коданайти соответствующую информацию В этом примере должна использоваться версия powermock v8 для полной поддержки функций 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. Состояние Сценарий 1
Когда заголовок запросаuid <= 1000Время:
- Напишите в шапке ответа:
x-unit-id: "3"
x-unit-region: "sh"
- Напишите в ответном трейлере:
x-api-version: "1.3.2"
- Напишите в теле ответа:
{"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. Сценарий условий 2
Когда заголовок запроса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),
},
}
})()
В этом сценарии код, заголовок, трейлер и тело ответа генерируются в соответствии с заголовком запроса и некоторыми встроенными или пользовательскими функциями. Тело ответа, полученное конечным клиентом, похоже на:
{
"timestamp": 1622093545,
"message": "this message is generated by javascript, your uid is: 2233",
"amount": 314
}
Он описывает относительно сложную сцену. Конечно, ваши потребности могут быть относительно простыми. Для настоящего боя давайте начнем с Hello World!
2. Начнем с Hello World
Этот пример можно найти вобразец коданайти соответствующую информацию
Сначала создайте файл конфигурации:
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/
Поместите скомпилированный 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. Сначала смоделируйте 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, вы можете видеть, что привет мир вернулся к нам!
➜ 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: 12
hello world!
2. Смоделируйте другой интерфейс 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
Создадим наш Greeter.proto в директории apis:
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Чтобы загрузить наш недавно написанный прото-файл:
➜ ./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
Вы можете видеть в журнале запуска, что наш недавно созданный прото-файл был загружен в 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!"}
Как видите, в него добавлен MockAPI с именем «hello_example_gRPC», и мы загружаем его с помощью следующей команды:
➜ 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, вы можете сначала загрузить Greeter.proto через BloomRPC, а затем вызвать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.MD
startTime := 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"
Как видите, наш интерфейс был успешно смоделирован!
Установить
Установить через 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 .