-1

I have a 3 grpc microservices r1, r2, r3 where r1 connect to r2 and r2 connect to r3 for response. All the 3 microservices are entirely different project and running on different port 8001, 8002, 8003. How can I write integration test where I can validate connectivity among microservices?

I have unit test cases written for each microservices but don’t know how to write a integration test in golang

1 Answers1

0

Simplest approach

Just start all of your microservices. Have a look at this working example for testing gRPC services. Here's how you might modify it to connect r1, r2, and r3:

  1. Start r3
  2. Create an r3 client
  3. Start r2, providing the r3 client to your r2 server implementation
  4. Create an r2 client
  5. Start r1, providing the r2 client to your r1 server implementation
  6. In your test, create an r1 client and test its functionality

Untested example:

const bufSize = 1024 * 1024

var l1, l2, l3 *bufconn.Listener

func init() {
    l3 = bufconn.Listen(bufSize)
    s3 := grpc.NewServer()
    pb.RegisterR3Server(s3, &r3server{})
    go func() {
        if err := s3.Serve(l3); err != nil {
            log.Fatal(err)
        }
    }()

    ctx := context.Background()
    conn3, err := grpc.DialContext(
        ctx, "bufnet",
        grpc.WithContextDialer(func(_ interface{}, _ string) (interface{}, error) {
            return l3.Dial()
        }),
        grpc.WithInsecure(),
    )
    if err != nil {
        log.Fatal(err)
    }
    c3 := pb.NewR3Client(conn3)

    l2 = bufconn.Listen(bufSize)
    s2 := grpc.NewServer()
    pb.RegisterR2Server(s2, &r2server{R3Client: c3})
    go func() {
        defer conn3.Close()
        if err := s2.Serve(l2); err != nil {
            log.Fatal(err)
        }
    }()
    
    conn2, err := grpc.DialContext(
        ctx, "bufnet",
        grpc.WithContextDialer(func(_ interface{}, _ string) (interface{}, error) {
            return l2.Dial()
        }),
        grpc.WithInsecure(),
    )
    if err != nil {
        log.Fatal(err)
    }
    c2 := pb.NewR2Client(conn2)

    l1 = bufconn.Listen(bufSize)
    s1 := grpc.NewServer()
    pb.RegisterR1Server(s1, &r1server{R2Client: c2})
    go func() {
        defer conn2.Close()
        if err := s1.Serve(l1); err != nil {
            log.Fatal(err)
        }
    }()
}

func bufDialer(ctx context.Context, address string) (net.Conn, error) {
    return l1.Dial()
}

func TestSayHello(t *testing.T) {
    ctx := context.Background()
    conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
    if err != nil {
        t.Fatal(err)
    }
    defer conn.Close()

    client := pb.NewR1Client(conn)
    resp, err := client.SayHello(ctx, &pb.HelloRequest{Name: "test"})
    if err != nil {
        t.Fatal(err)
    }

    if resp.GetMessage() != "Hello test" {
        t.Fatal("hello reply must be 'Hello test'")
    }
}

A more integration test-y approach

Use Testcontainers-go, and start each microservice in sequence on the same Docker network.