{"id":15642855,"url":"https://github.com/nhatthm/grpcmock","last_synced_at":"2025-07-10T20:33:29.752Z","repository":{"id":37414184,"uuid":"422365598","full_name":"nhatthm/grpcmock","owner":"nhatthm","description":"gRPC Test Utilities for Golang","archived":false,"fork":false,"pushed_at":"2024-10-13T12:44:54.000Z","size":555,"stargazers_count":75,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-29T16:06:48.772Z","etag":null,"topics":["go","golang","grpc","mock","test"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nhatthm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"nhatthm","custom":"donate.nhat.me"}},"created_at":"2021-10-28T21:52:51.000Z","updated_at":"2024-10-13T12:44:56.000Z","dependencies_parsed_at":"2024-01-24T18:28:41.659Z","dependency_job_id":"aa6e3653-1682-41fb-be64-8d66e34e296f","html_url":"https://github.com/nhatthm/grpcmock","commit_stats":{"total_commits":154,"total_committers":3,"mean_commits":"51.333333333333336","dds":0.4415584415584416,"last_synced_commit":"50e31e1ff6f24d0aed79c857b937543c80de4134"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nhatthm%2Fgrpcmock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nhatthm%2Fgrpcmock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nhatthm%2Fgrpcmock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nhatthm%2Fgrpcmock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nhatthm","download_url":"https://codeload.github.com/nhatthm/grpcmock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248045230,"owners_count":21038553,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["go","golang","grpc","mock","test"],"created_at":"2024-10-03T11:57:52.595Z","updated_at":"2025-04-09T13:05:15.329Z","avatar_url":"https://github.com/nhatthm.png","language":"Go","funding_links":["https://github.com/sponsors/nhatthm","donate.nhat.me"],"categories":["Go"],"sub_categories":[],"readme":"\u003e ⚠️ From `v0.20.0`, the project will be rebranded to `go.nhat.io/grpcmock`. `v0.19.0` is the last version with `github.com/nhatthm/grpcmock`.\n\n# gRPC Test Utilities for Golang\n\n[![GitHub Releases](https://img.shields.io/github/v/release/nhatthm/grpcmock)](https://github.com/nhatthm/grpcmock/releases/latest)\n[![Build Status](https://github.com/nhatthm/grpcmock/actions/workflows/test.yaml/badge.svg)](https://github.com/nhatthm/grpcmock/actions/workflows/test.yaml)\n[![codecov](https://codecov.io/gh/nhatthm/grpcmock/branch/master/graph/badge.svg?token=eTdAgDE2vR)](https://codecov.io/gh/nhatthm/grpcmock)\n[![Go Report Card](https://goreportcard.com/badge/go.nhat.io/grpcmock)](https://goreportcard.com/report/go.nhat.io/grpcmock)\n[![GoDevDoc](https://img.shields.io/badge/dev-doc-00ADD8?logo=go)](https://pkg.go.dev/go.nhat.io/grpcmock)\n[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](http://donate.nhat.me)\n\nTest gRPC service and client like a pro.\n\n## Table of Contents\n\n- [Prerequisites](#prerequisites)\n- [Install](#install)\n- [Usage](#usage)\n    - [Mock a gRPC server](#mock-a-grpc-server)\n        - [Unary Method](#unary-method)\n        - [Client-Stream Method](#client-stream-method)\n        - [Server-Stream Method](#server-stream-method)\n        - [Bidirectional-Stream Method](#bidirectional-stream-method)\n    - [Invoke a gRPC method](#invoke-a-grpc-method)\n        - [Unary Method](#unary-method-1)\n        - [Client-Stream Method](#client-stream-method-1)\n        - [Server-Stream Method](#server-stream-method-1)\n        - [Bidirectional-Stream Method](#bidirectional-stream-method-1)\n\n## Prerequisites\n\n- `Go \u003e= 1.23`\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n## Install\n\n```bash\ngo get go.nhat.io/grpcmock\n```\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n## Usage\n\n### Mock a gRPC server\n\nRead more about [mocking a gRPC server](resources/docs/SERVER.md)\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n#### Unary Method\n\nRead more about [mocking a Unary Method](resources/docs/SERVER.md#mock-a-unary-method)\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.nhat.io/grpcmock\"\n\txassert \"go.nhat.io/grpcmock/assert\"\n)\n\nfunc TestGetItems(t *testing.T) {\n\tt.Parallel()\n\n\texpected := \u0026Item{Id: 42, Name: \"Item 42\"}\n\n\t_, d := grpcmock.MockServerWithBufConn(\n\t\tgrpcmock.RegisterService(RegisterItemServiceServer),\n\t\tfunc(s *grpcmock.Server) {\n\t\t\ts.ExpectUnary(\"myservice/GetItem\").\n\t\t\t\tWithHeader(\"locale\", \"en-US\").\n\t\t\t\tWithPayload(\u0026GetItemRequest{Id: 42}).\n\t\t\t\tReturn(expected)\n\t\t},\n\t)(t)\n\n\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)\n\tdefer cancel()\n\n\tout := \u0026Item{}\n\n\terr := grpcmock.InvokeUnary(ctx,\n\t\t\"myservice/GetItem\",\n\t\t\u0026GetItemRequest{Id: 42}, out,\n\t\tgrpcmock.WithHeader(\"locale\", \"en-US\"),\n\t\tgrpcmock.WithContextDialer(d),\n\t\tgrpcmock.WithInsecure(),\n\t)\n\n\txassert.EqualMessage(t, expected, out)\n\tassert.NoError(t, err)\n}\n```\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n#### Client-Stream Method\n\nRead more about [mocking a Client-Stream Method](resources/docs/SERVER.md#mock-a-client-stream-method)\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.nhat.io/grpcmock\"\n\txassert \"go.nhat.io/grpcmock/assert\"\n)\n\nfunc TestCreateItems(t *testing.T) {\n\tt.Parallel()\n\n\texpected := \u0026CreateItemsResponse{NumItems: 1}\n\n\t_, d := grpcmock.MockServerWithBufConn(\n\t\tgrpcmock.RegisterService(RegisterItemServiceServer),\n\t\tfunc(s *grpcmock.Server) {\n\t\t\ts.ExpectClientStream(\"myservice/CreateItems\").\n\t\t\t\tWithPayload([]*Item{{Id: 42}}).\n\t\t\t\tReturn(expected)\n\t\t},\n\t)(t)\n\n\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)\n\tdefer cancel()\n\n\tout := \u0026CreateItemsResponse{}\n\terr := grpcmock.InvokeClientStream(ctx, \"myservice/CreateItems\",\n\t\tgrpcmock.SendAll([]*Item{{Id: 42}}), out,\n\t\tgrpcmock.WithContextDialer(d),\n\t\tgrpcmock.WithInsecure(),\n\t)\n\n\txassert.EqualMessage(t, expected, out)\n\tassert.NoError(t, err)\n}\n```\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n#### Server-Stream Method\n\nRead more about [mocking a Server-Stream Method](resources/docs/SERVER.md#mock-a-server-stream-method)\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.nhat.io/grpcmock\"\n\txassert \"go.nhat.io/grpcmock/assert\"\n)\n\nfunc TestListItems(t *testing.T) {\n\tt.Parallel()\n\n\texpected := []*Item{\n\t\t{Id: 41, Name: \"Item 41\"},\n\t\t{Id: 42, Name: \"Item 42\"},\n\t}\n\n\t_, d := grpcmock.MockServerWithBufConn(\n\t\tgrpcmock.RegisterService(RegisterItemServiceServer),\n\t\tfunc(s *grpcmock.Server) {\n\t\t\ts.ExpectServerStream(\"myservice/ListItems\").\n\t\t\t\tWithPayload(\u0026ListItemsRequest{}).\n\t\t\t\tReturn(expected)\n\t\t},\n\t)(t)\n\n\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)\n\tdefer cancel()\n\n\tactual := make([]*Item, 0)\n\n\terr := grpcmock.InvokeServerStream(ctx,\n\t\t\"myservice/ListItems\",\n\t\t\u0026ListItemsRequest{},\n\t\tgrpcmock.RecvAll(\u0026actual),\n\t\tgrpcmock.WithContextDialer(d),\n\t\tgrpcmock.WithInsecure(),\n\t)\n\n\tassert.NoError(t, err)\n\tassert.Len(t, actual, len(expected))\n\n\tfor i := 0; i \u003c len(expected); i++ {\n\t\txassert.EqualMessage(t, expected[i], actual[i])\n\t}\n}\n```\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n#### Bidirectional-Stream Method\n\nRead more about [mocking a Bidirectional-Stream Method](resources/docs/SERVER.md#mock-a-bidirectional-stream-method)\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.nhat.io/grpcmock\"\n\txassert \"go.nhat.io/grpcmock/assert\"\n\t\"google.golang.org/grpc\"\n)\n\nfunc TestTransformItems(t *testing.T) {\n\tt.Parallel()\n\n\texpected := []*Item{\n\t\t{Id: 41, Name: \"Item 41\"},\n\t\t{Id: 42, Name: \"Item 42\"},\n\t}\n\n\t_, d := grpcmock.MockServerWithBufConn(\n\t\tgrpcmock.RegisterService(RegisterItemServiceServer),\n\t\tfunc(s *grpcmock.Server) {\n\t\t\ts.ExpectBidirectionalStream(\"myservice/TransformItems\").\n\t\t\t\tRun(func(ctx context.Context, s grpc.ServerStream) error {\n\t\t\t\t\tfor {\n\t\t\t\t\t\titem := \u0026Item{}\n\t\t\t\t\t\terr := s.RecvMsg(item)\n\n\t\t\t\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\titem.Name = fmt.Sprintf(\"Modified #%d\", item.Id)\n\n\t\t\t\t\t\tif err := s.SendMsg(item); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\t)(t)\n\n\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)\n\tdefer cancel()\n\n\tin := []*Item{\n\t\t{Id: 41, Name: \"Item 41\"},\n\t\t{Id: 42, Name: \"Item 42\"},\n\t}\n\n\tactual := make([]*Item, 0)\n\n\terr := grpcmock.InvokeBidirectionalStream(ctx,\n\t\t\"myservice/TransformItems\",\n\t\tgrpcmock.SendAndRecvAll(in, \u0026actual),\n\t\tgrpcmock.WithContextDialer(d),\n\t\tgrpcmock.WithInsecure(),\n\t)\n\n\tassert.NoError(t, err)\n\tassert.Len(t, actual, len(expected))\n\n\tfor i := 0; i \u003c len(expected); i++ {\n\t\txassert.EqualMessage(t, expected[i], actual[i])\n\t}\n}\n```\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n### Invoke a gRPC method\n\n#### Unary Method\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"go.nhat.io/grpcmock\"\n\t\"google.golang.org/grpc/test/bufconn\"\n)\n\nfunc getItem(l *bufconn.Listener, id int32) (*Item, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)\n\tdefer cancel()\n\n\tout := \u0026Item{}\n\terr := grpcmock.InvokeUnary(ctx, \"myservice/GetItem\",\n\t\t\u0026GetItemRequest{Id: id}, out,\n\t\tgrpcmock.WithHeader(\"Locale\", \"en-US\"),\n\t\tgrpcmock.WithBufConnDialer(l),\n\t\tgrpcmock.WithInsecure(),\n\t)\n\n\treturn out, err\n}\n```\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n#### Client-Stream Method\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"go.nhat.io/grpcmock\"\n\t\"google.golang.org/grpc/test/bufconn\"\n)\n\nfunc createItems(l *bufconn.Listener, items []*Item) (*CreateItemsResponse, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)\n\tdefer cancel()\n\n\tout := \u0026CreateItemsResponse{}\n\terr := grpcmock.InvokeClientStream(ctx, \"myservice/CreateItems\",\n\t\tgrpcmock.SendAll(items), out,\n\t\tgrpcmock.WithBufConnDialer(l),\n\t\tgrpcmock.WithInsecure(),\n\t)\n\n\treturn out, err\n}\n```\n\nOr with a custom handler\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"go.nhat.io/grpcmock\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/test/bufconn\"\n)\n\nfunc createItems(l *bufconn.Listener, items []*Item) (*CreateItemsResponse, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)\n\tdefer cancel()\n\n\tout := \u0026CreateItemsResponse{}\n\terr := grpcmock.InvokeClientStream(ctx, \"myservice/CreateItems\",\n\t\tfunc(s grpc.ClientStream) error {\n\t\t\t// Handle the stream here.\n\t\t\treturn nil\n\t\t},\n\t\tout,\n\t\tgrpcmock.WithBufConnDialer(l),\n\t\tgrpcmock.WithInsecure(),\n\t)\n\n\treturn out, err\n}\n```\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n#### Server-Stream Method\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"go.nhat.io/grpcmock\"\n\t\"google.golang.org/grpc/test/bufconn\"\n)\n\nfunc listItems(l *bufconn.Listener) ([]*Item, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)\n\tdefer cancel()\n\n\tout := make([]*Item, 0)\n\terr := grpcmock.InvokeServerStream(ctx, \"myservice/ListItems\",\n\t\t\u0026ListItemsRequest{},\n\t\tgrpcmock.RecvAll(\u0026out),\n\t\tgrpcmock.WithBufConnDialer(l),\n\t\tgrpcmock.WithInsecure(),\n\t)\n\n\treturn out, err\n}\n```\n\nOr with a custom handler\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"go.nhat.io/grpcmock\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/test/bufconn\"\n)\n\nfunc listItems(l *bufconn.Listener) ([]*Item, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)\n\tdefer cancel()\n\n\tout := make([]*Item, 0)\n\terr := grpcmock.InvokeServerStream(ctx, \"myservice/ListItems\",\n\t\t\u0026ListItemsRequest{},\n\t\tfunc(s grpc.ClientStream) error {\n\t\t\t// Handle the stream here.\n\t\t\treturn nil\n\t\t},\n\t\tgrpcmock.WithBufConnDialer(l),\n\t\tgrpcmock.WithInsecure(),\n\t)\n\n\treturn out, err\n}\n```\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n#### Bidirectional-Stream Method\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"go.nhat.io/grpcmock\"\n\t\"google.golang.org/grpc/test/bufconn\"\n)\n\nfunc transformItems(l *bufconn.Listener, in []*Item) ([]*Item, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)\n\tdefer cancel()\n\n\tout := make([]*Item, 0)\n\terr := grpcmock.InvokeBidirectionalStream(ctx, \"myservice/TransformItems\",\n\t\tgrpcmock.SendAndRecvAll(in, \u0026out),\n\t\tgrpcmock.WithBufConnDialer(l),\n\t\tgrpcmock.WithInsecure(),\n\t)\n\n\treturn out, err\n}\n```\n\nOr with a custom handler\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"go.nhat.io/grpcmock\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/test/bufconn\"\n)\n\nfunc transformItems(l *bufconn.Listener, in []*Item) ([]*Item, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)\n\tdefer cancel()\n\n\tout := make([]*Item, 0)\n\terr := grpcmock.InvokeBidirectionalStream(ctx, \"myservice/TransformItems\",\n\t\tfunc(s grpc.ClientStream) error {\n\t\t\t// Handle the stream here.\n\t\t\treturn nil\n\t\t},\n\t\tgrpcmock.WithBufConnDialer(l),\n\t\tgrpcmock.WithInsecure(),\n\t)\n\n\treturn out, err\n}\n```\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n## Donation\n\nIf this project help you reduce time to develop, you can give me a cup of coffee :)\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n\n### Paypal donation\n\n[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](http://donate.nhat.me)\n\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;or scan this\n\n\u003cimg src=\"https://user-images.githubusercontent.com/1154587/113494222-ad8cb200-94e6-11eb-9ef3-eb883ada222a.png\" width=\"147px\" /\u003e\n\n[\u003csub\u003e\u003csup\u003e[table of contents]\u003c/sup\u003e\u003c/sub\u003e](#table-of-contents)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnhatthm%2Fgrpcmock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnhatthm%2Fgrpcmock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnhatthm%2Fgrpcmock/lists"}