测试使用TWIRP开发的RPC服务

问题描述

我想测试一个样本twirp RPC服务。示例服务来自Twirp official website

Protobuf的定义如下:

Syntax = "proto3";

package helloservice;
option go_package = "helloservice";

service HelloWorld {
  rpc Hello(HelloReq) returns (HelloResp);
}

message HelloReq {
  string subject = 1;
}

message HelloResp {
  string text = 1;
}

服务器实现:

type HelloWorldServer struct{}

func (s *HelloWorldServer) Hello(ctx context.Context,req *pb.HelloReq) (*pb.HelloResp,error) {
    return &pb.HelloResp{Text: "Hello " + req.Subject},nil
}

我尝试了solution suggested here,但是ClientConn与HTTPClient之间有些混淆。到目前为止,我有这个

var Once sync.Once
const bufSize = 1024 * 1024
var listener *bufconn.Listener

func InitTestServer(t *testing.T) *gomock.Controller {
    Once.Do(func(){
        listener = bufconn.Listen(bufSize)
        server := &server.HelloWorldServer{}
        twirpHandler := pb.NewHelloWorldServer(server,nil)
        mux := http.NewServeMux()
        mux.Handle(twirpHandler.PathPrefix(),twirpHandler)
        httpServer := http.Server{
            Handler: mux,}
        go func() {
            if err := httpServer.Serve(listener); err != nil {
                if err != http.ErrServerClosed {
                    log.Fatalln("Failed to start http listener","error",err)
                }
            }
        }()
    })
    ctrl := gomock.NewController(t)
    return ctrl
}

func bufDialer(context.Context,string) (net.Conn,error) {
    return listener.Dial()
}

func TestCreate(t *testing.T) {
    //ctrl := InitTestServer(t)
    InitTestServer(t)
    ctx := context.Background()
    conn,err := grpc.DialContext(ctx,"",grpc.WithInsecure(),grpc.WithContextDialer(bufDialer))
    // conn is of type *ClientConn
    if err != nil {
        t.Fatalf("Failed to dial bufnet: %v",err)
    }
    defer conn.Close()
    //NewHelloWorldJSONClient accepts only HTTPClient
    client := pb.NewHelloWorldJSONClient(conn)
    response,err := client.Hello(ctx,&pb.HelloReq{
        Subject: "sample",})
    t.Log(response,err)
}

有什么方法可以将其转换为另一种,还是有其他方法可以测试twirp RPC?

解决方法

您可以使用net/http/httptest完成这种测试。

  1. 使用pb.NewHelloWorldServer创建处理程序,并为其提供服务器实现结构。
  2. 使用处理程序创建httptest.NewServer
  3. .URL(或protobuf,或两者)中使用httptest服务器的pb.NewHelloWorldJSONClient

作为一个简单的例子:

package main

import (
    "context"
    "net/http"
    "net/http/httptest"
    "testing"

    pb "github.com/3ventic/twirphelloworld/rpc"
)

// InitTestServer initializes a test server for HelloWorld and returns its address
func InitTestServer() string {
    handler := pb.NewHelloWorldServer(&HelloWorldServer{})
    server := httptest.NewServer(handler)
    return server.URL
}

func TestHello(t *testing.T) {
    url := InitTestServer()
    clients := map[string]pb.HelloWorld{
        "json": pb.NewHelloWorldJSONClient(url,http.DefaultClient),"pb":   pb.NewHelloWorldProtobufClient(url,}

    for typ,client := range clients {
        t.Run(typ,func(t *testing.T) {
            ctx := context.Background()
            result,err := client.Hello(ctx,&pb.HelloReq{
                Subject: "test",})
            if err != nil {
                t.Error(err)
                t.FailNow()
            }
            if result.Text != "Hello test" {
                t.Errorf("result didn't match 'Hello test',was '%s'",result.Text)
            }
        })
    }
}

Full example available here