tutorial

45 Menggunakan httptest untuk Test End-to-End

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:

// note.go
type Note struct {
    ID   int    `json:"id"`
    Body string `json:"body"`
}

var notes = []Note{}
var currentID = 1

func createNoteHandler(w http.ResponseWriter, r *http.Request) {
    var note Note
    json.NewDecoder(r.Body).Decode(&note)
    note.ID = currentID
    currentID++
    notes = append(notes, note)
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(note)
}

func getNotesHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(notes)
}

Routing sederhana menggunakan http.ServeMux:

func NewRouter() http.Handler {
    mux := http.NewServeMux()
    mux.HandleFunc("/notes", func(w http.ResponseWriter, r *http.Request) {
        if r.Method == http.MethodPost {
            createNoteHandler(w, r)
        } else if r.Method == http.MethodGet {
            getNotesHandler(w, r)
        } else {
            http.NotFound(w, r)
        }
    })
    return mux
}

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.

func setupTestServer() *httptest.Server {
    router := NewRouter()
    server := httptest.NewServer(router)
    return server
}

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
func TestE2ENotesAPI(t *testing.T) {
    server := setupTestServer()
    defer server.Close()

    // Step 1: Create a note
    note := map[string]string{"body": "Belajar httptest"}
    payload, _ := json.Marshal(note)
    resp, err := http.Post(server.URL+"/notes",
        "application/json", bytes.NewBuffer(payload))
    require.NoError(t, err)
    require.Equal(t, http.StatusCreated, resp.StatusCode)
    var created Note
    json.NewDecoder(resp.Body).Decode(&created)
    resp.Body.Close()
    assert.Equal(t, "Belajar httptest", created.Body)
    assert.NotZero(t, created.ID)

    // Step 2: Get all notes
    resp, err = http.Get(server.URL + "/notes")
    require.NoError(t, err)
    require.Equal(t, http.StatusOK, resp.StatusCode)
    var notesResp []Note
    json.NewDecoder(resp.Body).Decode(&notesResp)
    resp.Body.Close()
    assert.Len(t, notesResp, 1)
    assert.Equal(t, created, notesResp[0])
}

3. Diagram Alur Test

Mari visualisasikan alurnya dengan diagram mermaid yang sederhana:

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?

func TestCreateNote_MalformedPayload(t *testing.T) {
    server := setupTestServer()
    defer server.Close()

    resp, err := http.Post(server.URL+"/notes",
        "application/json", strings.NewReader("{broken_json}"))
    require.NoError(t, err)
    require.Equal(t, http.StatusBadRequest, resp.StatusCode)
}

Tambahkan validasi di handler:

func createNoteHandler(w http.ResponseWriter, r *http.Request) {
    var note Note
    err := json.NewDecoder(r.Body).Decode(&note)
    if err != nil {
        http.Error(w, "Invalid payload", http.StatusBadRequest)
        return
    }
    // ... lanjutkan proses seperti sebelumnya
}

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!

comments powered by Disqus

Topik Terhangat

programming
271
tutorial
138
tips-and-trick
43
jaringan
28
hardware
11
linux
4
kubernetes
1