iT邦幫忙

2025 iThome 鐵人賽

DAY 13
1

在前幾天,我們完成了單元測試、pprof 優化,以及 SearchService 介面層。今天的目標是:

  • 建立一個 fake Elasticsearch(假實作),把它注入 REST API,完成一個「從 /search 呼叫到 service,再到假 ES」的 整合測試

Step 1:為什麼要用假 ES?

Elasticsearch 很重,不可能每次 CI/CD 都啟一個 cluster。

這時候,我們會用 fake service 來模擬 ES 行為:

  • :無需真的啟動 ES。
  • 可控:回傳固定的測資。
  • 安全:先確保 API flow 正常,再連真實 ES。

Step 2:定義假 ES

前一天我們有定義:

// search.go
type SearchService interface {
    Search(ctx context.Context, query string) ([]SearchResult, error)
}

type SearchResult struct {
    ID    string
    Title string
}

今天我們新增一個 fake 版本

// fake_es.go
package search

import "context"

type FakeSearchService struct{}

func (f *FakeSearchService) Search(ctx context.Context, query string) ([]SearchResult, error) {
    if query == "golang" {
        return []SearchResult{
            {ID: "1", Title: "Golang Official"},
            {ID: "2", Title: "Go by Example"},
        }, nil
    }
    return []SearchResult{}, nil
}


Step 3:整合 API

我們的 /search handler 透過 DI(依賴注入)傳入 service:

// handler.go
type SearchHandler struct {
    Service SearchService
}

func (h *SearchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    q := r.URL.Query().Get("q")

    results, err := h.Service.Search(ctx, q)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    json.NewEncoder(w).Encode(results)
}


Step 4:E2E 測試

接著,用 httptest 模擬 HTTP 請求,寫第一個整合測試:

// handler_test.go
func TestSearchHandler_E2E(t *testing.T) {
    fake := &search.FakeSearchService{}
    h := &SearchHandler{Service: fake}

    req := httptest.NewRequest("GET", "/search?q=golang", nil)
    w := httptest.NewRecorder()

    h.ServeHTTP(w, req)

    resp := w.Result()
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        t.Fatalf("expected 200, got %d", resp.StatusCode)
    }

    var got []search.SearchResult
    if err := json.NewDecoder(resp.Body).Decode(&got); err != nil {
        t.Fatalf("decode error: %v", err)
    }

    if len(got) != 2 {
        t.Errorf("expected 2 results, got %d", len(got))
    }
}

這裡我們完全沒有啟動 ES,只是透過假 service,驗證 API → Service → Response 這條路徑是通的。


Step 5:小結

今天我們完成了 E2E 測試雛型

  1. 定義假 ES,模擬搜尋結果。
  2. 把 fake service 注入 handler。
  3. 使用 httptest 驗證整條 API 流程。

明天,我們就要真的打通 Elasticsearch,寫一個最小 smoke test,讓 /search 能對接本地 ES。


上一篇
Day 12 - Elasticsearch 介面層:定義 SearchService
下一篇
Day 14 - 打通真路徑:連上本機 ES 的 smoke test
系列文
用 Golang + Elasticsearch + Kubernetes 打造雲原生搜尋服務14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言