Skip to content

nhatthm/grpcmock

Folders and files

NameName
Last commit message
Last commit date
Aug 19, 2024
Dec 19, 2023
Dec 7, 2021
Aug 19, 2024
May 28, 2024
May 28, 2024
Dec 19, 2023
Aug 28, 2022
Aug 19, 2024
Dec 19, 2023
Aug 19, 2024
May 28, 2024
Dec 19, 2023
May 28, 2024
May 28, 2024
May 28, 2024
May 28, 2024
Aug 24, 2022
Aug 24, 2022
Sep 16, 2024
Oct 13, 2021
Sep 16, 2024
Aug 19, 2024
May 28, 2024
Oct 31, 2021
May 28, 2024
Feb 6, 2023
Oct 28, 2021
Jan 25, 2025
Jan 25, 2025
May 28, 2024
Dec 10, 2021
Aug 28, 2022
Dec 19, 2023
Dec 19, 2023
May 28, 2024
May 28, 2024
Sep 16, 2024
May 28, 2024
Feb 8, 2023
Dec 19, 2023
May 28, 2024
May 28, 2024
Dec 19, 2023
Aug 19, 2024
Sep 16, 2024
May 28, 2024
Dec 19, 2023
May 28, 2024
Nov 20, 2021
May 28, 2024
Dec 19, 2023

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]