⚠️ Fromv0.20.0
, the project will be rebranded togo.nhat.io/grpcmock
.v0.19.0
is the last version withgit.luolix.top/nhatthm/grpcmock
.
Test gRPC service and client like a pro.
Go >= 1.21
go get go.nhat.io/grpcmock
Read more about mocking a gRPC server
Read more about mocking a Unary Method
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)
}
Read more about mocking a Client-Stream Method
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)
}
Read more about mocking a Server-Stream Method
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])
}
}
Read more about mocking a Bidirectional-Stream Method
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])
}
}
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
}
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
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
}
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
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
}
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
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
}
If this project help you reduce time to develop, you can give me a cup of coffee :)
or scan this