为了账号安全,请及时绑定邮箱和手机立即绑定

欺骗 grpc UnaryHandler 在 Go 中进行 gRPC 单元测试

欺骗 grpc UnaryHandler 在 Go 中进行 gRPC 单元测试

Go
慕的地6264312 2023-07-17 14:50:15
我正在努力提高 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 抱怨:无法在拦截器的参数中使用 authService.GetToken (type func(context.Context, *AuthData) (*Token, error)) 作为类型 grpc.UnaryHandler我继续编写了一个正确满足以下条件的虚拟函数:func genericHandler(ctx context.Context, req interface{}) (interface{}, error) {    return req, nil}这很好,因为我在测试拦截器时并不特别需要运行任何特定方法。然而,我很好奇为什么实际方法不满足约束,因为(根据我的理解)每当我在野外调用该 RPC 时,它都会被传递到底层的拦截器函数。最可能的解释是 grpc UnaryHandler 没有做我想象的那样,但是它做了什么?
查看完整描述

1 回答

?
茅侃侃

TA贡献1842条经验 获得超21个赞

不,函数


GetToken(ctx context.Context, req *AuthData) (*Token, error)

与以下类型不同


type UnaryHandler func(ctx context.Context, req interface{}) (interface{}, error)

InGetToken第二个参数req的类型为*AuthData,而 inUnaryHandler req的类型为interface{}。返回的*Token类型与 不同interface{}。这就是为什么不能GetToken直接传递给拦截器的原因。


在你的 grpc 服务中,你可以编写类似的方法


GetToken(ctx context.Context, req *AuthData) (*Token, error)

作为处理程序来完成您的服务器工作。然而,它并不UnaryHandler像人们想象的那样。


大部分转换是由 grpc/protobuf 代码生成器完成的。根据您的原型定义,它会生成一个接口,如下所示:


type XXXServer interface {

    GetToken(ctx context.Context, req *AuthData) (*Token, error)

}

您可以看到您的处理程序满足的是这个接口(而不是 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)

}

在 this 内部UnaryHandler,它将把您的服务器转换为接口XXXServer,然后调用您的处理程序(您的代码)。这显示了如何interceptor调用它。


查看完整回答
反对 回复 2023-07-17
  • 1 回答
  • 0 关注
  • 65 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信