Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
29 Aug 2025 · 5 mnt baca ·Artikel 82 / 110
Go

82. Test dengan `bufconn` tanpa Network

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

82. Test dengan bufconn tanpa Network

Saat membangun aplikasi berbasis gRPC, salah satu tantangan terbesar adalah melakukan testing secara reliable tanpa harus berurusan dengan kompleksitas jaringan yang nyata. Biasanya, test gRPC dilakukan dengan mensimulasikan server berjalan di port tertentu, lalu client mengirim request ke sana. Namun cara ini memiliki sejumlah keterbatasan, antara lain:

  • Lambat, karena harus benar-benar membuka socket network
  • Rentan terhadap race condition port, terutama jika dijalankan secara parallel
  • Mengganggu jika ada network firewall, resource limit, dsb

Di dunia Go, ada sebuah solusi elegan untuk masalah ini, yaitu: bufconn , singkatan dari buffered connection. Dengan bufconn, kita bisa membuat client dan server gRPC saling berkomunikasi lewat memory buffer (mirip pipe), tanpa benar-benar membuka koneksi jaringan. Artikel ini membahas konsep, praktik, kelebihan, kekurangan, hingga simulasi penggunaan bufconn untuk testing gRPC di Go.


Apa itu bufconn?

Secara sederhana, bufconn adalah package yang menyediakan implementasi net.Listener, namun transport-nya menggunakan memory buffer alih-alih jaringan. Ini memungkinkan dependency injection pada saat testing, cukup dengan mengganti listener server menjadi bufconn.Listen ketimbang net.Listen.

Ilustrasinya kira-kira seperti berikut:

MERMAID
flowchart LR
    A[gRPC Client] --(memory buffer)--> B[gRPC Server]
    subgraph Normal Network
        style A fill:#f9f,stroke:#333,stroke-width:2px
        style B fill:#bbf,stroke:#333,stroke-width:2px
    end
    A2[gRPC Client] --TCP socket--> B2[gRPC Server]
    subgraph Bufconn
        style A2 fill:#f6f,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5
        style B2 fill:#bdf,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5
    end

Pada diagram di atas, bagian kiri memperlihatkan test via memory buffer (bufconn), sedangkan kanan dengan network asli (TCP socket).


Kenapa Menggunakan bufconn?

Ada beberapa alasan mengapa sebaiknya mulai melirik bufconn di workflow testing Anda:

KelebihanKekurangan
Cepat – tidak ada latency jaringanTidak coverage code di level transport (TCP)
Tidak terganggu race pada portTidak catch bug config TLS/real network
Aman untuk paralel testPerlu sedikit setup kode tambahan
Mudah diintegrasikan dalam test Go (testing package)Tidak ideal untuk integration test yang butuh real env

Contoh Skenario: Testing gRPC Service Calculator

Sebagai ilustrasi, misalkan kita punya service gRPC sederhana bernama Calculator dengan satu method Add.

1. Definisi Service (proto)

protobuf
 1// calculator.proto
 2syntax = "proto3";
 3package calculator;
 4
 5service Calculator {
 6  rpc Add (AddRequest) returns (AddReply);
 7}
 8
 9message AddRequest {
10  int32 a = 1;
11  int32 b = 2;
12}
13
14message AddReply {
15  int32 result = 1;
16}

Generate kode Go-nya (pastikan anda sudah install protoc-gen-go-grpc dan protoc-gen-go):

shell
1protoc --go_out=. --go-grpc_out=. calculator.proto

2. Implementasi Server Go

go
 1// calculator_server.go
 2package main
 3
 4import (
 5  pb "path/to/calculatorpb"
 6  "context"
 7)
 8
 9type calculatorServer struct {
10  pb.UnimplementedCalculatorServer
11}
12
13func (s *calculatorServer) Add(ctx context.Context, req *pb.AddRequest) (*pb.AddReply, error) {
14  sum := req.A + req.B
15  return &pb.AddReply{Result: sum}, nil
16}

3. Setup Testing dengan Bufconn

Mari kita menulis test integration tanpa jaringan:

go
 1// calculator_test.go
 2package main
 3
 4import (
 5  "context"
 6  "log"
 7  "net"
 8  "testing"
 9  "google.golang.org/grpc"
10  "google.golang.org/grpc/test/bufconn"
11
12  pb "path/to/calculatorpb"
13)
14
15const bufSize = 1024 * 1024
16
17var lis *bufconn.Listener
18
19func bufDialer(context.Context, string) (net.Conn, error) {
20  return lis.Dial()
21}
22
23func startTestGrpcServer() {
24  lis = bufconn.Listen(bufSize)
25  s := grpc.NewServer()
26  pb.RegisterCalculatorServer(s, &calculatorServer{})
27  go func() {
28    if err := s.Serve(lis); err != nil {
29      log.Fatalf("Server exited with: %v", err)
30    }
31  }()
32}
33
34func TestAdd_WithBufconn(t *testing.T) {
35  startTestGrpcServer()
36
37  ctx := context.Background()
38  conn, err := grpc.DialContext(
39    ctx,
40    "bufnet",
41    grpc.WithContextDialer(bufDialer),
42    grpc.WithInsecure(),
43  )
44  if err != nil {
45    t.Fatalf("Failed to dial bufnet: %v", err)
46  }
47  defer conn.Close()
48
49  client := pb.NewCalculatorClient(conn)
50  resp, err := client.Add(ctx, &pb.AddRequest{A: 10, B: 30})
51  if err != nil {
52    t.Fatalf("Add failed: %v", err)
53  }
54  if resp.Result != 40 {
55    t.Fatalf("Expected 40, got %d", resp.Result)
56  }
57}

4. Simulasi Eksekusi Test

Mari lihat flow internal ketika test dijalankan:

MERMAID
sequenceDiagram
    participant T as Test Runner (Go `testing`)
    participant C as gRPC Client
    participant S as gRPC Server (di memory buffer)

    T->>S: Jalankan gRPC server pada bufconn.Listener
    T->>C: Buat koneksi gRPC client via bufDialer
    C->>S: Kirim request Add(10, 30) (via buffer memory)
    S->>S: Proses & balas AddReply(40)
    S->>C: Balas reply ke client (via buffer)
    C->>T: Hasil dikembalikan ke test runner

Keuntungan terbesar: Test berjalan full di memory, cepat, tanpa butuh port, bebas gangguan race/OS.


Tips Production Use

  • Gunakan bufconn hanya untuk unit/integration test, bukan real production!
  • Cocok untuk testing service yang sangat banyak dependensi network atau sulit mockup.
  • Untuk test dengan interaksi sungguhan (TLS, firewall), tetap butuh e2e test via real socket.

Kesimpulan

Testing dengan bufconn membuka cara baru untuk speed up dan merapikan ekosistem test gRPC. Kita tak lagi harus woro-woro soal port bentrok atau race condition pada integration test. Cukup injeksi bufconn.Listener, dan seluruh tes cukup berjalan di memory tanpa satu byte pun dilepas ke jaringan asli.

Summary benefit menggunakan bufconn pada testing gRPC:

  • Eliminasi dependency jaringan
  • Meningkatkan determinasi dan kecepatan test
  • Aman untuk paralel test dan CI/CD pipeline

Ingat: Gunakan bufconn untuk level integration/unit test, tapi jangan lupakan e2e test pada env sungguhan untuk coverage penuh.

Selamat mencoba bufconn di workflow gRPC testing Anda! 🚀


Referensi Lanjut:

Artikel Terkait

💬 Komentar