我正在努力提高我的 Go gRPC 服务器的覆盖率,但我在为服务器的拦截器功能编写测试时遇到了麻烦,因为我无法有意义地满足 UnaryHandler
类型。
我有一个函数 Interceptor
具有以下签名:
Interceptor func(
ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler, // <- my issue comes from here
) (interface{}, error)
我假设任何 gRPC 方法都会满足 UnaryHandler
的签名:
type UnaryHandler func(ctx context.Context, req interface{}) (interface{}, error)
所以我尝试传入一个带有这个签名的方法:
GetToken(ctx context.Context, req *AuthData) (*Token, error)
我想这会起作用,因为这是拦截器实际正在做的事情(转发那个 RPC),但出于某种原因 Go 提示:
cannot use authService.GetToken (type func(context.Context, *AuthData) (*Token, error)) as type grpc.UnaryHandler in argument to Interceptor
我继续写了一个正确满足的虚拟函数:
func genericHandler(ctx context.Context, req interface{}) (interface{}, error) {
return req, nil
}
这很好,因为我并不特别需要在测试拦截器时运行任何特定方法。但是,我很好奇为什么实际方法不满足约束,因为(根据我的理解)每当我在野外调用该 RPC 时,它都会被传递给引擎盖下的拦截器函数。
最可能的解释是 grpc UnaryHandler 没有按照我的想法去做,但是它做了什么?
最佳答案
不,函数
GetToken(ctx context.Context, req *AuthData) (*Token, error)
与
不是同一类型type UnaryHandler func(ctx context.Context, req interface{}) (interface{}, error)
在GetToken
中,第二个参数req
的类型是*AuthData
,而在UnaryHandler
中,req
属于 interface{}
类型。返回的 *Token
与 interface{}
的类型也不同。这就是为什么不能将 GetToken
直接传递给拦截器的原因。
在你的 grpc 服务中,你会写这样的方法
GetToken(ctx context.Context, req *AuthData) (*Token, error)
作为执行服务器工作的处理程序。然而,它并不像人们想象的那样是一个 UnaryHandler
。
大部分转换是由grpc/protobuf 代码生成器完成的。根据您的原型(prototype)定义,它会生成一个接口(interface),如下所示:
type XXXServer interface {
GetToken(ctx context.Context, req *AuthData) (*Token, error)
}
您可以看到您的处理程序满足的是这个接口(interface)(而不是 UnaryHander)。
在幕后,如果您查看生成的 xxx.pb.go
文件,您会发现一些 _XXX_GetToken_Handler
实际上在执行处理程序工作。在此函数中,定义了一个(实际的)UnaryHandler
,如下所示:
func _XXX_GetToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
// skip other preparations...
//
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(XXXServer).GetToken(ctx, req.(*AuthData))
}
return interceptor(ctx, in, info, handler)
}
在这个 UnaryHandler
中,它会将您的服务器转换为 XXXServer
接口(interface),然后调用您的处理程序(您的代码)。这显示了如何调用 interceptor
。
关于go - 欺骗 grpc UnaryHandler 以在 Go 中对 gRPC 进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57681271/