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

45 Menggunakan `httptest` untuk Test End-to-End

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

45 Menggunakan httptest untuk Test End-to-End

Pengujian merupakan bagian tak terpisahkan dari pengembangan software modern. Salah satu tantangan utamanya adalah memastikan seluruh stack aplikasi berjalan sesuai ekspektasi, terutama untuk aplikasi berbasis HTTP seperti yang umum kita temui pada service berbasis Go. Dalam konteks ini, Go menyediakan paket httptest yang powerful untuk menguji aplikasi dari sudut pandang end-to-end (E2E).

Pada artikel ini, saya akan membahas praktik penggunaan httptest untuk test E2E di aplikasi Go. Penjelasan akan mencakup:

  • Apa itu httptest dan kegunaannya
  • Studi kasus aplikasi sederhana
  • Langkah-langkah membangun E2E test
  • Simulasi request-response
  • Tips & best practice
  • Tabel perbandingan
  • Diagram alur test

Mari kita mulai!


Apa Itu httptest?

httptest adalah paket resmi dari standar library Go yang menyediakan utilitas untuk pengujian HTTP. Paket ini biasanya digunakan untuk :

  • Membuat test server (httptest.NewServer)
  • Membuat request dan response recorder (httptest.NewRecorder)
  • Menguji handler dan end-point

Dengan paket ini, kita dapat mensimulasikan HTTP request/response tanpa harus menjalankan server secara penuh di luar testing environment. Cocok untuk test integration maupun E2E di aplikasi Go.


Studi Kasus: Aplikasi Notes API

Saya akan menggunakan studi kasus aplikasi API sederhana sebagai contoh — Notes API, dengan dua end-point:

  • POST /notes : membuat note baru
  • GET /notes : mengambil seluruh notes

Represtasikan handlers berikut:

go
 1// note.go
 2type Note struct {
 3    ID   int    `json:"id"`
 4    Body string `json:"body"`
 5}
 6
 7var notes = []Note{}
 8var currentID = 1
 9
10func createNoteHandler(w http.ResponseWriter, r *http.Request) {
11    var note Note
12    json.NewDecoder(r.Body).Decode(&note)
13    note.ID = currentID
14    currentID++
15    notes = append(notes, note)
16    w.WriteHeader(http.StatusCreated)
17    json.NewEncoder(w).Encode(note)
18}
19
20func getNotesHandler(w http.ResponseWriter, r *http.Request) {
21    w.Header().Set("Content-Type", "application/json")
22    json.NewEncoder(w).Encode(notes)
23}

Routing sederhana menggunakan http.ServeMux:

go
 1func NewRouter() http.Handler {
 2    mux := http.NewServeMux()
 3    mux.HandleFunc("/notes", func(w http.ResponseWriter, r *http.Request) {
 4        if r.Method == http.MethodPost {
 5            createNoteHandler(w, r)
 6        } else if r.Method == http.MethodGet {
 7            getNotesHandler(w, r)
 8        } else {
 9            http.NotFound(w, r)
10        }
11    })
12    return mux
13}

Implementasi Test End-to-End dengan httptest

Bagaimana cara menggunakan httptest untuk menguji API ini dari ujung ke ujung? Berikut langkah-langkah intinya:

1. Membuat Test Server

Gunakan httptest.NewServer untuk menjalankan handler sebagai server HTTP asli pada port random.

go
1func setupTestServer() *httptest.Server {
2    router := NewRouter()
3    server := httptest.NewServer(router)
4    return server
5}

2. Test flow: Simulasi Use Case E2E

Kita akan membuat satu integration test yang:

  1. Mengirim POST /notes dengan payload JSON
  2. Mengirim GET /notes dan mengecek note yang baru saja dibuat ada di hasil response
go
 1func TestE2ENotesAPI(t *testing.T) {
 2    server := setupTestServer()
 3    defer server.Close()
 4
 5    // Step 1: Create a note
 6    note := map[string]string{"body": "Belajar httptest"}
 7    payload, _ := json.Marshal(note)
 8    resp, err := http.Post(server.URL+"/notes",
 9        "application/json", bytes.NewBuffer(payload))
10    require.NoError(t, err)
11    require.Equal(t, http.StatusCreated, resp.StatusCode)
12    var created Note
13    json.NewDecoder(resp.Body).Decode(&created)
14    resp.Body.Close()
15    assert.Equal(t, "Belajar httptest", created.Body)
16    assert.NotZero(t, created.ID)
17
18    // Step 2: Get all notes
19    resp, err = http.Get(server.URL + "/notes")
20    require.NoError(t, err)
21    require.Equal(t, http.StatusOK, resp.StatusCode)
22    var notesResp []Note
23    json.NewDecoder(resp.Body).Decode(&notesResp)
24    resp.Body.Close()
25    assert.Len(t, notesResp, 1)
26    assert.Equal(t, created, notesResp[0])
27}

3. Diagram Alur Test

Mari visualisasikan alurnya dengan diagram mermaid yang sederhana:

MERMAID
sequenceDiagram
    participant T as Test Code
    participant S as httptest.Server
    participant H as Handlers

    T->>S: POST /notes (dengan payload)
    S->>H: createNoteHandler
    H-->>S: Response 201 (note baru)
    S-->>T: Kirim response 201

    T->>S: GET /notes
    S->>H: getNotesHandler
    H-->>S: Response 200 (daftar notes)
    S-->>T: Kirim response 200 beserta notes

Tabel: Kelebihan dan Kekurangan

AspekKelebihan httptestKekurangan httptest
DependencyTidak butuh server eksternalTidak bisa testing infra eksternal (misal koneksi DB sebenarnya)
SpeedSuper cepat, in-memoryTidak cover e2e sesungguhnya di production
RealismeMendekati testing nyata (full HTTP stack)Masih di lingkungan test, bukan real server
IsolasiMudah reset state, cocok untuk parallel testState sederhana, persistence terbatas

Simulasi Failure Case

Bagaimana jika kita ingin test error, misal payload malformed?

go
1func TestCreateNote_MalformedPayload(t *testing.T) {
2    server := setupTestServer()
3    defer server.Close()
4
5    resp, err := http.Post(server.URL+"/notes",
6        "application/json", strings.NewReader("{broken_json}"))
7    require.NoError(t, err)
8    require.Equal(t, http.StatusBadRequest, resp.StatusCode)
9}

Tambahkan validasi di handler:

go
1func createNoteHandler(w http.ResponseWriter, r *http.Request) {
2    var note Note
3    err := json.NewDecoder(r.Body).Decode(&note)
4    if err != nil {
5        http.Error(w, "Invalid payload", http.StatusBadRequest)
6        return
7    }
8    // ... lanjutkan proses seperti sebelumnya
9}

Tips dan Best Practice

  1. Gunakan httptest.NewServer untuk full handler test, bukan hanya unit handler.
  2. Pastikan state selalu reset sebelum setiap test E2E. Hindari side effect!
  3. Gunakan helper/setup function untuk memperpendek kode boilerplate test server.
  4. Gunakan assertion dari library seperti testify untuk pengecekan yang readable.
  5. Testing variasi edge-case (payload invalid, metode tak dikenali, dsb).

Kesimpulan

Dengan httptest, Go memungkinkan penulisan E2E test untuk API HTTP dengan mudah dan cepat, tanpa perlu server eksternal. Dari simulasi request hingga pengecekan response, kita dapat memastikan end-point berjalan sesuai ekspektasi sebelum naik ke lingkungan production.

Apakah httptest sudah otomatis cukup untuk semua kebutuhan E2E? Tidak selalu, terutama jika aplikasi Anda bergantung pada beberapa service eksternal. Namun, untuk sebagian besar kasus API Go, tes berbasis httptest adalah fondasi yang kuat dan sangat recommended untuk diterapkan sejak hari pertama development.

Integrasikan dengan pipeline CI Anda — dan nikmati proses confidence boost setiap fitur baru didorong!


Baca juga:

Selamat mencoba, dan semoga bermanfaat!

Artikel Terkait

💬 Komentar