Go如何编写Grpc测试

Go如何编写Grpc测试

我重写了公司原有的代码,对pb文件进行了更改,为了保持原有的功能保持正确性,我不得不进行测试,但是我没有找到任何一个关于Golang Grpc的测试,通过查找,可以不用开启Grcp客户端进行测试,只需要通过反射就可以调用到Grcp的方法,并进行测试。

一、导包

导入我们编写的文件,他们都在同一目录下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package pb_test

import (
"context"
"sync"
"testing"

pb2 "github.com/echoingtech/uc/proto"
"github.com/echoingtech/uc/service/user"

"github.com/echoingtech/uc/config"
"github.com/echoingtech/uc/domain"
"github.com/echoingtech/uc/presentation/mysql"

"github.com/micro/go-micro/registry/memory"
"github.com/micro/go-micro/server"
"github.com/micro/go-micro/server/grpc"
gc "google.golang.org/grpc"
)

二、初始化配置文件

初始化配置文件,我们可以在init方法中进行初始化,或者使用TestMain方法进行测试化。我选择了init方法,因为我不要那么复杂的初始化,并且比较容易编写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var userHandler pb2.UserHandler

func init() {
config.LoadConfig()
engineGroup := config.GetDB()
var (
userRepository domain.UserRepository
qqRepository domain.QQRepository
wechatRepository domain.WechatRepository
)
{
userRepository = mysql.NewUserRepository(engineGroup)
qqRepository = mysql.NewQqRepository(engineGroup)
wechatRepository = mysql.NewWechatRepository(engineGroup)
}
userService := user.NewService(userRepository, qqRepository, wechatRepository)
userHandler = NewUserAdapter

}

这里解释一下userHandler是我们通过pb文件生成的接口,而NewUserAdapter则是我们的实现类。通过依赖注入的方式使我们可以很方便的测试任何方法。

三、编写测试服务

我们注册一个服务,这个服务不需要通过网络。我们只需要在内存中通信就可以了,这可以的节省资源,并且启动很迅速。开启服务后我们通过s.Start()启动服务,并通过gc.Dial(s.Options().Address, gc.WithInsecure())进行拨号。现在我们可以进行测试了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
func TestGRPCServer(t *testing.T) {
r := memory.NewRegistry()
s := grpc.NewServer(
server.Name("foo"),
server.Registry(r),
)
if err := pb2.RegisterUserHandler(s, userHandler); err != nil {
t.Fatalf("failed to start: %v", err)
}

if err := s.Start(); err != nil {
t.Fatalf("failed to start: %v", err)
}

// check registration
services, err := r.GetService("foo")
if err != nil || len(services) == 0 {
t.Fatalf("failed to get service: %v # %d", err, len(services))
}

defer func() {
if err := s.Stop(); err != nil {
t.Fatalf("failed to stop: %v", err)
}
}()

cc, err := gc.Dial(s.Options().Address, gc.WithInsecure())
if err != nil {
t.Fatalf("failed to dial server: %v", err)
}
var wg sync.WaitGroup
wg.Add(1)
go getUserInfo(t, &wg, cc)
wg.Add(1)
go getQQInfo(t, &wg, cc)
wg.Add(1)
go getWechatInfo(t, &wg, cc)
wg.Wait()
}

四、通过异步的方式加速测试

我们通过sync.WaitGroup或者是用goroutinechan的组合,可以轻易的编写出异步的测试代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
func getUserInfo(t *testing.T, wg *sync.WaitGroup, cc *gc.ClientConn) {
func() {
defer wg.Done()
userRsp := pb2.UserResponse{}
if err := cc.Invoke(context.Background(), "/User/GetUser", &pb2.GetUserRequest{UserId: 86617739354963979}, &userRsp); err != nil {
t.Fatalf("error calling server: %v", err)
}
if userRsp.Code == 1 {
t.Fatalf("Got unexpected response %v", userRsp.Data)
} else {
t.Log(userRsp.Data)
}
}()
}

func getQQInfo(t *testing.T, wg *sync.WaitGroup, cc *gc.ClientConn) {
func() {
defer wg.Done()
userRsp := pb2.GetOpenIdResponse{}
if err := cc.Invoke(context.Background(), "/User/GetOpenId", &pb2.GetOpenIdRequest{
UserId: 86617739354963979,
Source: pb2.LoginSource_QQ,
AppId: "1109882002",
}, &userRsp); err != nil {
t.Fatalf("error calling server: %v", err)
}
if userRsp.Code == 1 {
t.Fatalf("Got unexpected response %v", userRsp.Message)
} else {
t.Log(userRsp.OpenId)
}
}()
}

func getWechatInfo(t *testing.T, wg *sync.WaitGroup, cc *gc.ClientConn) {
func() {
defer wg.Done()
userRsp := pb2.GetOpenIdResponse{}
if err := cc.Invoke(context.Background(), "/User/GetOpenId", &pb2.GetOpenIdRequest{
UserId: 86617739354963979,
Source: pb2.LoginSource_Weixin,
AppId: "wxaf7362726f135b5c",
}, &userRsp); err != nil {
t.Fatalf("error calling server: %v", err)
}
if userRsp.Code == 1 {
t.Fatalf("Got unexpected response %v", userRsp.Message)
} else {
t.Log(userRsp.OpenId)
}
}()
}

通过反射规则调用,规则是文件名/方法名,并且开头字母大写。

五、总结

到现在为止,已经不错了。我们可以很方便的测试我们编写的pb文件,并且这种测试是可以进行一次配置,多次测试的。通过异步使得测试更有效率,但是异步看起来还有些丑陋,可以使用goroutinechan模式做一些简化。

#

评论

`
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×