gRPC is increasing in popularity. Because of this, there may be a need to mock gRPC based services in early development and testing. This article shows current possibilities, as of mid of 2023.
In general we can divide existing software into two group - free and paid software. Obviously we are interested more in free option, so here we are looking more into that one.
Paid solutions
To keep all options available, it can be mentioned, at least one paid application that provides possibility of gRPC mocking.
Traffic Parrot, as stated on their web pages provides API and service simulation, service virtualization and API mocking software. Evaluation version supports wide range of protocols already, including gRPC.
There is also a possibility to request dedicated support for many others, as stated on their web
As we are interested in gRPC only here are links, that may be helpful: Resources:
Watching demo may be also a good idea for general overview, how most of mocks (also the free ones) work in general.
Free solutions
As there are free-of-charge solutions in the internet, let’s discuss them briefly, without getting into details too much.
Wiremock
Wiremock is java-based solution, that provides easily configurable stand-alone jar that can serve as a mock. Code repo is here Wiremock as of now, does not support gRPC natively. It’s planned to be included in the future, but without any hard dates or promises. Still, there is open source solution based on wiremock, called grpc-wiremock, that can be used.
This solution is dedicated to be run with docker. With some effort it’s also possible to run it locally. Proposed docker file example is provided within repo together with demo proto files and wiremock configuration. There is also .json file for testing with ghz binary available from this source. Setup is quite straightforward.
Example wallet service will be used for a quick demo.
Structure used for testing (with default content):
This service was successfully mocked with example provided by mock developer. For a reference same service will be used to test other mocks.
Mountebank
Mountebank is another great tool, that is used for mocking. Code can be found here. In a similar way as wiremock, it doesn’t support gRPC by default, but it’s possible to install plugin, that will make it working.
This can be done via npm:
1
npm install -g mountebank-grpc-mts
Then gRPC support should be added into configuration:
info: [mb:2525] Loaded custom protocol grpc info: [mb:2525] mountebank v2.8.2 now taking orders - point your browser to http://localhost:2525/ for help debug: [mb:2525] config: {"options":{"protofile":"protocols-grpc.json","port":2525,"noParse":false,"no-parse":false,"formatter":"mountebank-formatters","pidfile":"mb.pid","allowInjection":false,"allow-injection":false,"localOnly":false,"local-only":false,"ipWhitelist":["*"],"ip-whitelist":"*","mock":false,"debug":false,"origin":false,"apikey":null,"log":{"level":"debug","transports":{"console":{"colorize":true,"format":"%level: %message"},"file":{"path":"mb.log","format":"json"}}}},"process":{"nodeVersion":"v18.16.0","architecture":"x64","platform":"linux"}}
The structure in this case is slightly different than for wiremock:
1 2 3 4 5 6 7 8 9
proto ├── common.proto └── wallet.proto
imposters └── grpc.json
stubs └── wallet.balance.json
Content of proto directory is same as for wiremock and it is located in /tmp/mountebank/grpc/proto directory. imposters contains gRPC services definition:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
{ "protocol":"grpc", "port":4545, "loglevel":"debug", "recordRequests":true, "_note_services":"need the name of the package, service and protofile location for this to load", "services":{ "api.wallet.BalanceService":{"file":"wallet.proto"}, "api.wallet.WalletService":{"file":"wallet.proto"}
Important thing here is to point server to proto directory, where services and dependencies are defined. In stubs, there are responses definition in json format. In this case the content is:
info: [mb:2525] POST /imposters debug: [mb:2525] ::ffff:127.0.0.1:56886 => {"protocol":"grpc","port":4545,"loglevel":"debug","recordRequests":true,"_note_services":"need the name of the package, service and protofile location for this to load","services":{"api.wallet.BalanceService":{"file":"wallet.proto"},"api.wallet.WalletService":{"file":"wallet.proto"}},"options":{"protobufjs":{"_note":"any options to protobufjs","includeDirs":["/tmp/mountebank/grpc/proto"]}}} debug: [grpc:4545] {"port":4545,"encoding":"utf8","services":{"api.wallet.BalanceService":{"file":"wallet.proto"},"api.wallet.WalletService":{"file":"wallet.proto"}}} info: [grpc:4545] Open for business... info: [grpc:4545] server started on port '4545'
Response is successful, and in debug server messages can be seen how request was processed:
1 2 3 4 5 6 7
debug: [grpc:4545] sending unary-unary rpc debug: [grpc:4545] send request to mountebank debug: [grpc:4545] url='http://localhost:2525/imposters/4545/_requests', data='{"request":{"peer":"127.0.0.1:52350","path":"/api.wallet.BalanceService/getUserBalance","value":{"user_id":"1","currency":"EUR"},"metadata":{"initial":{"user-agent":"grpcurl/v1.8.7 grpc-go/1.48.0"}}}}' debug: [mb:2525] POST /imposters/4545/_requests debug: [grpc:4545] using predicate match: [{"equals":{"path":"/api.wallet.BalanceService/getUserBalance"},"caseSensitive":false}] debug: [grpc:4545] generating response from {"is":{"value":{"balance":{"amount":{"value":{"decimal":"0.0"},"value_present":true},"currency":{"value":"ANY","value_present":false}}}}} debug: [grpc:4545] response.data="{"response":{"value":{"balance":{"amount":{"value":{"decimal":"0.0"},"value_present":true},"currency":{"value":"ANY","value_present":false}}}}}"
In this way it was showed how mountebank can be used to work with gRPC.
Camouflage
Now we can take a look on the only mock server, that offer gRPC support “by default”. Camouflage is npm-installable application. Code is available in github repo. Again, we re-use protofiles from previous examples to check how mocking can be implemented.
After installing camouflage it should be initiated:
Prepared data should be placed in created structures:
1
$ cp -a /tmp/import/* /tmp/camouflage/grpc
Mock configuration should be align to our changes, to enable gRPC. You need to edit /tmp/camouflage/config.yml file. Backup of original file is backed up.
cd /tmp/camouflage/ camouflage --config config.yml
Following information from server logs is related with gRPC and provided setup:
1 2 3 4 5 6 7 8 9 10
<timestamp> debug: Found protofile: /tmp/camouflage/grpc/proto/common.proto <timestamp> debug: Found protofile: /tmp/camouflage/grpc/proto/wallet.proto <timestamp> debug: Using proto-loader config as: {"keepCase":true,"includeDirs":["./grpc/protos"]} <timestamp> debug: Ignoring protofiles: <timestamp> debug: Using insecure gRPC server credentials. <timestamp> debug: Registering Unary method: createTransaction <timestamp> debug: Registering method with server side streaming: searchTransaction <timestamp> debug: Registering Unary method: getUserBalance (node:1211) Warning: common.proto not found in any of the include paths ./grpc/protos <timestamp> info: Worker sharing gRPC server at 0.0.0.0:4312 ⛳