クローラをテストする場合の少し気を使ったテストサーバ

まだあまり細かい話は外に出せないですが, golang で Web クローラと API を使ったシステムを開発しています。

クローラを書くにあたり net/http/httptest を使ってこんなテスト用サーバを書いて対応しました。

package main

import (
  "fmt"
  "io/ioutil"
  "net/http"
  "net/http/httptest"
)

func testServer() *httptest.Server {
  server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    // User-Agent が想定してないものの場合 400
    if r.Header.Get("User-Agent") != "Mybot" {
      http.Error(w, "User-Agent is invalud", http.StatusBadRequest)
    }

    // Basic 認証が設定されている場合照合し判定
    // 不正な場合 401 を返す
    if authName, authPass, authStatus := r.BasicAuth(); authStatus {
      if authName != "correct-username" || authPass != "correct-password" {
        http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
      }
    }

    // サイト root はテストしないので 404
    if r.RequestURI == "" {
      // index page is always not found
      http.NotFound(w, r)
    }

    // RequestURI と同名のファイルを testdata ディレクトリから取得
    // 存在しなければ 404
    res, err := ioutil.ReadFile("../testdata" + r.RequestURI)
    if err != nil {
      http.NotFound(w, r)
    }

    // 取得したコンテンツを返す
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, str)
  }))
  return server
}

このテストサーバでテストしていること

このテストサーバを使ってクローラに対して次のようなテストを実施しています。

  • User-Agent が正しいものであること
  • Basic 認証下のコンテンツにアクセスできること
    • Basic 認証が通らなかった場合のクローラの処理
  • アクセスしたページのコンテンツを取得できること
    • ページが 404 だった場合のクローラの処理

使い方

golang の testing を利用してこんな感じでテストが書けます。

func TestFetch(t *testing.T) {
  ts := testServer()
  defer ts.Close()

  // Fetch は固有の User-Agent でページにアクセスしコンテンツを取得する
  data, err := Fetch(ts.URL+"/sample.html")

  if err != nil {
    t.Log(err)
    t.Error("Fetch() should not has error")
  }

  if len(data) == 0 {
    t.Error("Fetch() should return some data")
  }
}

testdata ディレクトリにファイルを用意しておけばもう少し複雑なテストも書くことができます。(書けています)

クローラを書いてみて感じたこと

  • 標準パッケージがしっかりしているので大体どうにかなる
  • 困ったら godoc とにらめっこするとなんとかなる
  • テストツールもあるので悩まなくていい(しかしどこかで違うツール入れるかもしれない)

悩んでいること

群馬で golang 書いてる人が見当たらない。