Pendahuluan

Go Fiber v3 adalah web framework minimalis yang memberikan performa tinggi dan struktur modular. Dalam pengembangan API modern, memastikan logika kritis berfungsi sebelum deployment sangat krusial agar kualitas tetap terjaga. Artikel ini mengulas strategi pengujian menyeluruh: mulai dari unit test service, pengujian handler HTTP berbasis table-driven, hingga mock database serta pengujian upload/import Excel. Tujuannya membantu engineer menyusun test cepat, stabil, dan mudah dirawat di pipeline CI.

Unit Test Service dengan Table-Driven

Unit test service menjadi langkah pertama memastikan business logic tertutup dengan baik. Format table-driven test menjaga struktur kasus tetap konsisten, memudahkan penambahan skenario baru, dan meminimalisir duplikasi kode.

func TestUserService_Create(t *testing.T) { t.Parallel()
    cases := []struct {
        name      string
        input     CreateUserInput
        repoFunc  func(*mockUserRepo, CreateUserInput)
        expectErr bool
    }{
        // tambahkan kasus valid, invalid, conflict, dll.
    }

    for _, tc := range cases {
        tc := tc
        t.Run(tc.name, func(t *testing.T) {
            t.Parallel()
            repo := newMockUserRepo(t)
            tc.repoFunc(repo, tc.input)
            svc := NewUserService(repo)
            got, err := svc.Create(context.Background(), &tc.input)
            if tc.expectErr {
                require.Error(t, err)
                return
            }
            require.NoError(t, err)
            require.Equal(t, expectedUser, got)
        })
    }
}

Pastikan setiap kasus menyetel repoFunc yang mereplikasi perilaku repository agar test tetap terisolasi dan deterministik. Table-driven memudahkan menambahkan skenario validasi input, konflik database, ataupun error yang disengaja tanpa mengubah kerangka utama test.

Pengujian Handler HTTP Fiber

Setelah service stabil, level berikutnya adalah pengujian HTTP handler. Fiber menyediakan app.Test(req) sehingga handler dapat diuji end-to-end dari routing, validasi payload, hingga respons JSON.

func TestRegisterHandler(t *testing.T) {
    app := fiber.New()
    handler := NewRegisterHandler(mockService)
    app.Post("/register", handler.Handle)
    payload := `{"email":"user@example.com","password":"secret"}`
    req := httptest.NewRequest(http.MethodPost, "/register", strings.NewReader(payload))
    req.Header.Set("Content-Type", "application/json")

    res, _ := app.Test(req)
    require.Equal(t, http.StatusCreated, res.StatusCode)
    body, _ := io.ReadAll(res.Body)
    require.JSONEq(t, `{"status":"ok","data":{"email":"user@example.com"}}`, string(body))
}

Gunakan require.JSONEq agar pengujian tidak sensitif terhadap urutan field. Untuk memverifikasi validasi input, simulasi request tak lengkap:

func TestRegisterHandler_BadPayload(t *testing.T) {
    app := fiber.New()
    handler := NewRegisterHandler(mockService)
    app.Post("/register", handler.Handle)

    req := httptest.NewRequest(http.MethodPost, "/register", strings.NewReader(`{}`))
    req.Header.Set("Content-Type", "application/json")
    res, _ := app.Test(req)

    require.Equal(t, http.StatusBadRequest, res.StatusCode)
    body, _ := io.ReadAll(res.Body)
    require.Contains(t, string(body), "email is required")
}

Pastikan validator dijalankan di handler atau middleware yang sama dengan produksi agar hasil pengujian mencerminkan perilaku sebenarnya.

Mock Repository dan Database

Mocking repository penting agar unit test terpisah dari database nyata dan bisa menghasilkan error deterministik. Gunakan testify/mock atau interface kustom yang mendukung dependency injection.

type UserRepository interface {
    Create(ctx context.Context, user *User) error
    GetByEmail(ctx context.Context, email string) (*User, error)
}

type mockUserRepo struct {
    mock.Mock
}

func (m *mockUserRepo) Create(ctx context.Context, user *User) error {
    return m.Called(ctx, user).Error(0)
}

Siapkan skenario untuk:

  • Success case mencocokkan hasil dengan data input.
  • Conflict entry memicu error dan memverifikasi handler mengembalikan status 409.
  • Timeout/connection error memicu context.DeadlineExceeded dan ditransformasikan menjadi status 503.

Mock memungkinkan Anda menulis pengujian ini tanpa terhubung ke database sungguhan, sekaligus memaksa service menangani retry atau rollback sesuai kebutuhan.

Pengujian Upload/Import Excel

Testing file upload—terutama Excel—mengharuskan simulasi multipart request dan validasi parsing. Berikut langkah umum:

  1. Buat file Excel dummy yang disimpan di folder testdata. Anda bisa menggunakan paket seperti excelize untuk generate sekali lalu commit.
  2. Gunakan multipart.NewWriter untuk membangun request upload inklusif field lain seperti user_id atau metadata.
  3. Handler menyimpan file sementara, memanggil parser dan worker atau service yang memproses data.
  4. Lengkapi test untuk error path, misalnya worker queue gagal enqueue.

Contoh test error worker enqueue:

func TestImportExcelHandler_WorkerEnqueueError(t *testing.T) {
    app := fiber.New()
    handler := NewImportHandler(mockWorkerAdapter)
    app.Post("/import", handler.Handle)

    payload := newMultipartPayload(t, "testdata/users.xlsx")
    req := httptest.NewRequest(http.MethodPost, "/import", payload.Body)
    req.Header.Set("Content-Type", payload.ContentType)

    mockWorkerAdapter.On("Enqueue", mock.Anything).Return(errors.New("queue error"))

    res, _ := app.Test(req)
    require.Equal(t, http.StatusServiceUnavailable, res.StatusCode)
    body, _ := io.ReadAll(res.Body)
    require.Contains(t, string(body), "worker enqueue failed")
}

Pastikan handler menangani penyimpanan file sementara dan membersihkan resource di akhir. Mock worker adapter memungkinkan Anda memverifikasi bahwa behavior enqueue error dikonversi ke respons yang sesuai tanpa menjalankan queue nyata.

Kesimpulan

Testing API Go Fiber v3 membutuhkan pendekatan berlapis: unit test service table-driven, pengujian handler HTTP menyeluruh, repository mocking, serta skenario upload/import file yang realistis. Dengan pola ini, tim engineering bisa membangun tuis yang stabil, mudah diperluas, dan memberikan kepercayaan tinggi sebelum setiap deployment.