Overview
上記で書いた gRPC サーバーを local で立ち上げる方法を下に、local で起動したその gRPC サーバーを利用して pubsub の動作(今回は subscriber の動作)をエミュレートするテストを書いてみます。
local でテスト用の pubsub クライアントを実装する
// grpc サーバーを起動する listener, err := net.Listen("tcp", "localhost:0") if err != nil { t.Fatal(err) } ts := grpc.NewServer() go func() { if err := ts.Serve(listener); err != nil { panic(err) } }() // 略 // テスト用の pubsub の Fake サービスを用意する。 type testSubscribeServer struct { pubsubpb.UnimplementedSubscriberServer } // subscriber の fake サーバーを起動した gPRC のサーバーに登録する tss := &testSubscribeServer{} pubsubpb.RegisterSubscriberServer(ts, tss) // local の gRPC に向けた grpc のコネクションを作成し、そのコネクションを使って pubsub クライアントを生成する。 conn, err := grpc.NewClient(listener.Addr().String(), grpc.WithInsecure()) if err != nil { t.Fatal(err) } client, _ = pubsub.NewClient(ctx, "test-project", option.WithGRPCConn(conn), option.WithoutAuthentication())
subscriber のサーバーを用意する場合以下のようにエミュレートしたい RPC のプロセスを mock で実装しておく必要があります。
type testSubscribeServer struct { pubsubpb.UnimplementedSubscriberServer } func (s testSubscribeServer) StreamingPull(r pubsubpb.Subscriber_StreamingPullServer) error { r.Send(&pubsubpb.StreamingPullResponse{ ReceivedMessages: []*pubsubpb.ReceivedMessage{ { AckId: "ack-id", Message: &pubsubpb.PubsubMessage{ Data: []byte("test-message"), }, }, }, }) return nil }
今回は streaming-pull の API をエミュレートするために StreamingPull の interface を Fake サービスに実装しました。 pubsub 含め GCP の各種サービスでエミュレートしたいプロセスがあるときは Fake サービスに interface を実装すればよいです。
なお、StreamingPull のプロセスをエミュレートできるとこの Receive 処理の検証が local で可能です。
pubsub の場合は https://github.com/googleapis/google-cloud-go/blob/main/pubsub/apiv1/pubsubpb/pubsub.pb.go にある Unimplemented{$Hoge}Server
に生えている interface を見ればエミュレートしたいプロセスをテストサーバーに生やせばよいです。
GCP のサービス全般、gRPC が必要なことが多いのでこの google-cloud-go の中にあるサンプルを探してみるのは良いかもしれません。
まとめ
pubsub に限らず gRPC サーバーが必要になるととたんにテストが多少難解になります。
pubsub のようにそもそもリモートでもテストがしづらいサービスなどを利用してるときは簡易的な動作検証は local で出来ると開発効率は上がることもあるので覚えてて損はない手法かなと思いました。