问题描述
我想测试一个样本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
完成这种测试。
- 使用
pb.NewHelloWorldServer
创建处理程序,并为其提供服务器实现结构。 - 使用处理程序创建
httptest.NewServer
。 - 在
.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)
}
})
}
}