You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go中GRPC流Send函数测试:如何触发Send失败场景

问题:如何在真实gRPC服务端/客户端环境下触发Send方法失败进行测试

我有一个Go语言的gRPC服务端流函数:

func (server *Server) GetClients(req *iam.GetClientsRequest, client iam.IAM_GetClientsServer) error {
    ctx := client.(interface{ Context() context.Context }).Context()

    userID, err := getUserIDStream(client)
    if err != nil {
        return err
    }

    clients, err := server.db.QueryByUserID(ctx, userID)
    if err != nil {
        return grpc.Errorf(codes.Internal, apiutils.ServerError)
    }

    for _, value := range clients {
        converted, err := server.fromInternalClient(value)
        if err != nil {
            return err
        }

        if err := client.Send(converted); err != nil {
            return err
        }
    }

    return nil
}

我的测试代码如下:

It("GetClients - Send fails - Error", func() {

    handler := createHandler(db)
    lis := bufconn.Listen(bufSize)
    server := grpc.NewServer()

    iam.RegisterIAMServer(server, NewServer(handler))
    go func() {
        if err := server.Serve(lis); err != nil {
            log.Fatalf("Server exited with error: %v", err)
        }
    }()

    defer lis.Close()
    defer server.GracefulStop()

    conn, err := grpc.DialContext(context.Background(), "bufnet",
        grpc.WithContextDialer(createBufDialier(lis)), grpc.WithInsecure())
    Expect(err).ShouldNot(HaveOccurred())
    defer conn.Close()
    client := iam.NewIAMClient(conn)

    cclient, _ := client.GetClients(addAccessToken(context.Background()), new(iam.GetClientsRequest))
    resp, err := cclient.Recv()

    Expect(resp).Should(BeNil())
    Expect(err).Should(HaveOccurred())
    Expect(err.Error()).Should(Equal(message))
})

我遇到的问题是:不清楚如何触发Send方法的失败来测试响应。由于我使用的是真实的测试服务端和客户端,不想采用Mock方式,请问有没有可行的办法?


解决方法

方案1:主动关闭客户端连接

在客户端获取到流客户端后,立即关闭gRPC连接,服务端执行Send操作时会因为连接已断开而返回错误。修改后的测试代码如下:

It("GetClients - Send fails - Error", func() {
    handler := createHandler(db)
    lis := bufconn.Listen(bufSize)
    server := grpc.NewServer()

    iam.RegisterIAMServer(server, NewServer(handler))
    go func() {
        if err := server.Serve(lis); err != nil {
            log.Fatalf("Server exited with error: %v", err)
        }
    }()

    defer lis.Close()
    defer server.GracefulStop()

    conn, err := grpc.DialContext(context.Background(), "bufnet",
        grpc.WithContextDialer(createBufDialier(lis)), grpc.WithInsecure())
    Expect(err).ShouldNot(HaveOccurred())
    client := iam.NewIAMClient(conn)

    cclient, _ := client.GetClients(addAccessToken(context.Background()), new(iam.GetClientsRequest))
    // 主动关闭连接,触发服务端Send失败
    conn.Close()
    
    resp, err := cclient.Recv()

    Expect(resp).Should(BeNil())
    Expect(err).Should(HaveOccurred())
    Expect(err.Error()).Should(Equal(message))
})

方案2:取消客户端上下文

创建可取消的上下文传入GetClients,获取流客户端后立即取消上下文,服务端的Send操作会因为上下文被取消而失败。修改后的测试代码如下:

It("GetClients - Send fails - Error", func() {
    handler := createHandler(db)
    lis := bufconn.Listen(bufSize)
    server := grpc.NewServer()

    iam.RegisterIAMServer(server, NewServer(handler))
    go func() {
        if err := server.Serve(lis); err != nil {
            log.Fatalf("Server exited with error: %v", err)
        }
    }()

    defer lis.Close()
    defer server.GracefulStop()

    conn, err := grpc.DialContext(context.Background(), "bufnet",
        grpc.WithContextDialer(createBufDialier(lis)), grpc.WithInsecure())
    Expect(err).ShouldNot(HaveOccurred())
    defer conn.Close()
    client := iam.NewIAMClient(conn)

    // 创建可取消的上下文
    ctx, cancel := context.WithCancel(addAccessToken(context.Background()))
    cclient, _ := client.GetClients(ctx, new(iam.GetClientsRequest))
    // 立即取消上下文
    cancel()
    
    resp, err := cclient.Recv()

    Expect(resp).Should(BeNil())
    Expect(err).Should(HaveOccurred())
    Expect(err.Error()).Should(Equal(message))
})

注意事项

  • 不同gRPC版本返回的错误信息可能存在差异,需要根据实际运行结果调整断言的错误内容。
  • 如果数据库返回的客户端数据量较大,也可以在服务端循环Send的过程中执行关闭连接或取消上下文的操作,同样能触发失败。

内容的提问来源于stack exchange,提问作者Woody1193

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 21:05:21