Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/nhatthm/grpcmock

gRPC Test Utilities for Golang
https://github.com/nhatthm/grpcmock

go golang grpc mock test

Last synced: 7 days ago
JSON representation

gRPC Test Utilities for Golang

Awesome Lists containing this project

README

        

> ⚠️ 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`.

# gRPC Test Utilities for Golang

[![GitHub Releases](https://img.shields.io/github/v/release/nhatthm/grpcmock)](https://github.com/nhatthm/grpcmock/releases/latest)
[![Build Status](https://github.com/nhatthm/grpcmock/actions/workflows/test.yaml/badge.svg)](https://github.com/nhatthm/grpcmock/actions/workflows/test.yaml)
[![codecov](https://codecov.io/gh/nhatthm/grpcmock/branch/master/graph/badge.svg?token=eTdAgDE2vR)](https://codecov.io/gh/nhatthm/grpcmock)
[![Go Report Card](https://goreportcard.com/badge/go.nhat.io/grpcmock)](https://goreportcard.com/report/go.nhat.io/grpcmock)
[![GoDevDoc](https://img.shields.io/badge/dev-doc-00ADD8?logo=go)](https://pkg.go.dev/go.nhat.io/grpcmock)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](http://donate.nhat.me)

Test gRPC service and client like a pro.

## Table of Contents

- [Prerequisites](#prerequisites)
- [Install](#install)
- [Usage](#usage)
- [Mock a gRPC server](#mock-a-grpc-server)
- [Unary Method](#unary-method)
- [Client-Stream Method](#client-stream-method)
- [Server-Stream Method](#server-stream-method)
- [Bidirectional-Stream Method](#bidirectional-stream-method)
- [Invoke a gRPC method](#invoke-a-grpc-method)
- [Unary Method](#unary-method-1)
- [Client-Stream Method](#client-stream-method-1)
- [Server-Stream Method](#server-stream-method-1)
- [Bidirectional-Stream Method](#bidirectional-stream-method-1)

## Prerequisites

- `Go >= 1.21`

[[table of contents]](#table-of-contents)

## Install

```bash
go get go.nhat.io/grpcmock
```

[[table of contents]](#table-of-contents)

## Usage

### Mock a gRPC server

Read more about [mocking a gRPC server](resources/docs/SERVER.md)

[[table of contents]](#table-of-contents)

#### Unary Method

Read more about [mocking a Unary Method](resources/docs/SERVER.md#mock-a-unary-method)

```go
package main

import (
"context"
"testing"
"time"

"github.com/stretchr/testify/assert"
"go.nhat.io/grpcmock"
xassert "go.nhat.io/grpcmock/assert"
)

func TestGetItems(t *testing.T) {
t.Parallel()

expected := &Item{Id: 42, Name: "Item 42"}

_, d := grpcmock.MockServerWithBufConn(
grpcmock.RegisterService(RegisterItemServiceServer),
func(s *grpcmock.Server) {
s.ExpectUnary("myservice/GetItem").
WithHeader("locale", "en-US").
WithPayload(&GetItemRequest{Id: 42}).
Return(expected)
},
)(t)

ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

out := &Item{}

err := grpcmock.InvokeUnary(ctx,
"myservice/GetItem",
&GetItemRequest{Id: 42}, out,
grpcmock.WithHeader("locale", "en-US"),
grpcmock.WithContextDialer(d),
grpcmock.WithInsecure(),
)

xassert.EqualMessage(t, expected, out)
assert.NoError(t, err)
}
```

[[table of contents]](#table-of-contents)

#### Client-Stream Method

Read more about [mocking a Client-Stream Method](resources/docs/SERVER.md#mock-a-client-stream-method)

```go
package main

import (
"context"
"testing"
"time"

"github.com/stretchr/testify/assert"
"go.nhat.io/grpcmock"
xassert "go.nhat.io/grpcmock/assert"
)

func TestCreateItems(t *testing.T) {
t.Parallel()

expected := &CreateItemsResponse{NumItems: 1}

_, d := grpcmock.MockServerWithBufConn(
grpcmock.RegisterService(RegisterItemServiceServer),
func(s *grpcmock.Server) {
s.ExpectClientStream("myservice/CreateItems").
WithPayload([]*Item{{Id: 42}}).
Return(expected)
},
)(t)

ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

out := &CreateItemsResponse{}
err := grpcmock.InvokeClientStream(ctx, "myservice/CreateItems",
grpcmock.SendAll([]*Item{{Id: 42}}), out,
grpcmock.WithContextDialer(d),
grpcmock.WithInsecure(),
)

xassert.EqualMessage(t, expected, out)
assert.NoError(t, err)
}
```

[[table of contents]](#table-of-contents)

#### Server-Stream Method

Read more about [mocking a Server-Stream Method](resources/docs/SERVER.md#mock-a-server-stream-method)

```go
package main

import (
"context"
"testing"
"time"

"github.com/stretchr/testify/assert"
"go.nhat.io/grpcmock"
xassert "go.nhat.io/grpcmock/assert"
)

func TestListItems(t *testing.T) {
t.Parallel()

expected := []*Item{
{Id: 41, Name: "Item 41"},
{Id: 42, Name: "Item 42"},
}

_, d := grpcmock.MockServerWithBufConn(
grpcmock.RegisterService(RegisterItemServiceServer),
func(s *grpcmock.Server) {
s.ExpectServerStream("myservice/ListItems").
WithPayload(&ListItemsRequest{}).
Return(expected)
},
)(t)

ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

actual := make([]*Item, 0)

err := grpcmock.InvokeServerStream(ctx,
"myservice/ListItems",
&ListItemsRequest{},
grpcmock.RecvAll(&actual),
grpcmock.WithContextDialer(d),
grpcmock.WithInsecure(),
)

assert.NoError(t, err)
assert.Len(t, actual, len(expected))

for i := 0; i < len(expected); i++ {
xassert.EqualMessage(t, expected[i], actual[i])
}
}
```

[[table of contents]](#table-of-contents)

#### Bidirectional-Stream Method

Read more about [mocking a Bidirectional-Stream Method](resources/docs/SERVER.md#mock-a-bidirectional-stream-method)

```go
package main

import (
"context"
"errors"
"fmt"
"io"
"testing"
"time"

"github.com/stretchr/testify/assert"
"go.nhat.io/grpcmock"
xassert "go.nhat.io/grpcmock/assert"
"google.golang.org/grpc"
)

func TestTransformItems(t *testing.T) {
t.Parallel()

expected := []*Item{
{Id: 41, Name: "Item 41"},
{Id: 42, Name: "Item 42"},
}

_, d := grpcmock.MockServerWithBufConn(
grpcmock.RegisterService(RegisterItemServiceServer),
func(s *grpcmock.Server) {
s.ExpectBidirectionalStream("myservice/TransformItems").
Run(func(ctx context.Context, s grpc.ServerStream) error {
for {
item := &Item{}
err := s.RecvMsg(item)

if errors.Is(err, io.EOF) {
return nil
}

if err != nil {
return err
}

item.Name = fmt.Sprintf("Modified #%d", item.Id)

if err := s.SendMsg(item); err != nil {
return err
}
}
})
},
)(t)

ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

in := []*Item{
{Id: 41, Name: "Item 41"},
{Id: 42, Name: "Item 42"},
}

actual := make([]*Item, 0)

err := grpcmock.InvokeBidirectionalStream(ctx,
"myservice/TransformItems",
grpcmock.SendAndRecvAll(in, &actual),
grpcmock.WithContextDialer(d),
grpcmock.WithInsecure(),
)

assert.NoError(t, err)
assert.Len(t, actual, len(expected))

for i := 0; i < len(expected); i++ {
xassert.EqualMessage(t, expected[i], actual[i])
}
}
```

[[table of contents]](#table-of-contents)

### Invoke a gRPC method

#### Unary Method

```go
package main

import (
"context"
"time"

"go.nhat.io/grpcmock"
"google.golang.org/grpc/test/bufconn"
)

func getItem(l *bufconn.Listener, id int32) (*Item, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

out := &Item{}
err := grpcmock.InvokeUnary(ctx, "myservice/GetItem",
&GetItemRequest{Id: id}, out,
grpcmock.WithHeader("Locale", "en-US"),
grpcmock.WithBufConnDialer(l),
grpcmock.WithInsecure(),
)

return out, err
}
```

[[table of contents]](#table-of-contents)

#### Client-Stream Method

```go
package main

import (
"context"
"time"

"go.nhat.io/grpcmock"
"google.golang.org/grpc/test/bufconn"
)

func createItems(l *bufconn.Listener, items []*Item) (*CreateItemsResponse, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

out := &CreateItemsResponse{}
err := grpcmock.InvokeClientStream(ctx, "myservice/CreateItems",
grpcmock.SendAll(items), out,
grpcmock.WithBufConnDialer(l),
grpcmock.WithInsecure(),
)

return out, err
}
```

Or with a custom handler

```go
package main

import (
"context"
"time"

"go.nhat.io/grpcmock"
"google.golang.org/grpc"
"google.golang.org/grpc/test/bufconn"
)

func createItems(l *bufconn.Listener, items []*Item) (*CreateItemsResponse, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

out := &CreateItemsResponse{}
err := grpcmock.InvokeClientStream(ctx, "myservice/CreateItems",
func(s grpc.ClientStream) error {
// Handle the stream here.
return nil
},
out,
grpcmock.WithBufConnDialer(l),
grpcmock.WithInsecure(),
)

return out, err
}
```

[[table of contents]](#table-of-contents)

#### Server-Stream Method

```go
package main

import (
"context"
"time"

"go.nhat.io/grpcmock"
"google.golang.org/grpc/test/bufconn"
)

func listItems(l *bufconn.Listener) ([]*Item, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

out := make([]*Item, 0)
err := grpcmock.InvokeServerStream(ctx, "myservice/ListItems",
&ListItemsRequest{},
grpcmock.RecvAll(&out),
grpcmock.WithBufConnDialer(l),
grpcmock.WithInsecure(),
)

return out, err
}
```

Or with a custom handler

```go
package main

import (
"context"
"time"

"go.nhat.io/grpcmock"
"google.golang.org/grpc"
"google.golang.org/grpc/test/bufconn"
)

func listItems(l *bufconn.Listener) ([]*Item, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

out := make([]*Item, 0)
err := grpcmock.InvokeServerStream(ctx, "myservice/ListItems",
&ListItemsRequest{},
func(s grpc.ClientStream) error {
// Handle the stream here.
return nil
},
grpcmock.WithBufConnDialer(l),
grpcmock.WithInsecure(),
)

return out, err
}
```

[[table of contents]](#table-of-contents)

#### Bidirectional-Stream Method

```go
package main

import (
"context"
"time"

"go.nhat.io/grpcmock"
"google.golang.org/grpc/test/bufconn"
)

func transformItems(l *bufconn.Listener, in []*Item) ([]*Item, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

out := make([]*Item, 0)
err := grpcmock.InvokeBidirectionalStream(ctx, "myservice/TransformItems",
grpcmock.SendAndRecvAll(in, &out),
grpcmock.WithBufConnDialer(l),
grpcmock.WithInsecure(),
)

return out, err
}
```

Or with a custom handler

```go
package main

import (
"context"
"time"

"go.nhat.io/grpcmock"
"google.golang.org/grpc"
"google.golang.org/grpc/test/bufconn"
)

func transformItems(l *bufconn.Listener, in []*Item) ([]*Item, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
defer cancel()

out := make([]*Item, 0)
err := grpcmock.InvokeBidirectionalStream(ctx, "myservice/TransformItems",
func(s grpc.ClientStream) error {
// Handle the stream here.
return nil
},
grpcmock.WithBufConnDialer(l),
grpcmock.WithInsecure(),
)

return out, err
}
```

[[table of contents]](#table-of-contents)

## Donation

If this project help you reduce time to develop, you can give me a cup of coffee :)

[[table of contents]](#table-of-contents)

### Paypal donation

[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](http://donate.nhat.me)

       or scan this

[[table of contents]](#table-of-contents)