Skip to content

nhatthm/grpcmock

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

⚠️ 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 Build Status codecov Go Report Card GoDevDoc Donate

Test gRPC service and client like a pro.

Table of Contents

Prerequisites

  • Go >= 1.21

[table of contents]

Install

go get go.nhat.io/grpcmock

[table of contents]

Usage

Mock a gRPC server

Read more about mocking a gRPC server

[table of contents]

Unary Method

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)
}

[table of contents]

Client-Stream Method

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)
}

[table of contents]

Server-Stream Method

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])
	}
}

[table of contents]

Bidirectional-Stream Method

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])
	}
}

[table of contents]

Invoke a gRPC method

Unary Method

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]

Client-Stream Method

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
}

[table of contents]

Server-Stream Method

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
}

[table of contents]

Bidirectional-Stream Method

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
}

[table of contents]

Donation

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

[table of contents]

Paypal donation

paypal

       or scan this

[table of contents]