Cách kiểm tra lệnh gọi http trong Go bằng httptest


76

Tôi có mã sau:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "time"
)

type twitterResult struct {
    Results []struct {
        Text     string `json:"text"`
        Ids      string `json:"id_str"`
        Name     string `json:"from_user_name"`
        Username string `json:"from_user"`
        UserId   string `json:"from_user_id_str"`
    }
}

var (
  twitterUrl = "http://search.twitter.com/search.json?q=%23UCL"
  pauseDuration = 5 * time.Second
)

func retrieveTweets(c chan<- *twitterResult) {
    for {
        resp, err := http.Get(twitterUrl)
        if err != nil {
            log.Fatal(err)
        }

        defer resp.Body.Close()
        body, err := ioutil.ReadAll(resp.Body)
        r := new(twitterResult) //or &twitterResult{} which returns *twitterResult
        err = json.Unmarshal(body, &r)
        if err != nil {
            log.Fatal(err)
        }
        c <- r
        time.Sleep(pauseDuration)
    }

}

func displayTweets(c chan *twitterResult) {
    tweets := <-c
    for _, v := range tweets.Results {
        fmt.Printf("%v:%v\n", v.Username, v.Text)
    }

}

func main() {
    c := make(chan *twitterResult)
    go retrieveTweets(c)
    for {
        displayTweets(c)
    }

}

Tôi muốn viết một số thử nghiệm cho nó, nhưng tôi không chắc cách sử dụng gói httptest http://golang.org/pkg/net/http/httptest/ sẽ đánh giá cao một số gợi ý

Tôi đã nghĩ ra điều này (được sao chép một cách hổ thẹn từ các bài kiểm tra cho go OAuth https://code.google.com/p/goauth2/source/browse/oauth/oauth_test.go ):

var request = struct {
    path, query       string // request
    contenttype, body string // response
}{
    path:        "/search.json?",
    query:       "q=%23Kenya",
    contenttype: "application/json",
    body:        twitterResponse,
}

var (
    twitterResponse = `{ 'results': [{'text':'hello','id_str':'34455w4','from_user_name':'bob','from_user_id_str':'345424'}]}`
)

func TestRetrieveTweets(t *testing.T) {
    handler := func(w http.ResponseWriter, r *http.Request) {

        w.Header().Set("Content-Type", request.contenttype)
        io.WriteString(w, request.body)
    }

    server := httptest.NewServer(http.HandlerFunc(handler))
    defer server.Close()

    resp, err := http.Get(server.URL)
    if err != nil {
        t.Fatalf("Get: %v", err)
    }
    checkBody(t, resp, twitterResponse)
}

func checkBody(t *testing.T, r *http.Response, body string) {
    b, err := ioutil.ReadAll(r.Body)
    if err != nil {
        t.Error("reading reponse body: %v, want %q", err, body)
    }
    if g, w := string(b), body; g != w {
        t.Errorf("request body mismatch: got %q, want %q", g, w)
    }
}

Câu trả lời:


91

httptest thực hiện hai loại kiểm tra: phản hồi và máy chủ

Kiểm tra phản hồi:

func TestHeader3D(t *testing.T) {
    resp := httptest.NewRecorder()

    uri := "/3D/header/?"
    path := "/home/test"
    unlno := "997225821"

    param := make(url.Values)
    param["param1"] = []string{path}
    param["param2"] = []string{unlno}

    req, err := http.NewRequest("GET", uri+param.Encode(), nil)
    if err != nil {
            t.Fatal(err)
    }

    http.DefaultServeMux.ServeHTTP(resp, req)
    if p, err := ioutil.ReadAll(resp.Body); err != nil {
            t.Fail()
    } else {
            if strings.Contains(string(p), "Error") {
                    t.Errorf("header response shouldn't return error: %s", p)
            } else if !strings.Contains(string(p), `expected result`) {
                    t.Errorf("header response doen't match:\n%s", p)
            }
    }
}

Kiểm tra máy chủ (là những gì bạn cần sử dụng):

func TestIt(t *testing.T){
    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        fmt.Fprintln(w, `{"fake twitter json string"}`)
    }))
    defer ts.Close()

    twitterUrl = ts.URL
    c := make(chan *twitterResult)
    go retrieveTweets(c)

    tweet := <-c
    if tweet != expected1 {
        t.Fail()
    }
    tweet = <-c
    if tweet != expected2 {
        t.Fail()
    }
}

BTW, bạn không cần chuyển vào con trỏ của r, vì nó đã là một con trỏ.

err = json.Unmarshal(body, r)

CHỈNH SỬA: để kiểm tra trình ghi của tôi, tôi có thể sử dụng trình xử lý http của mình như thế này:

handler(resp, req)

Nhưng mã gốc của tôi không sử dụng mux mặc định (mà từ Gorilla / mux) và tôi có một số gói xung quanh mux, ví dụ: chèn ghi nhật ký máy chủ và thêm ngữ cảnh yêu cầu (Gorilla / context), vì vậy tôi phải bắt đầu từ mux và gọi ServeHTTP


12
Vui lòng thêm mã hoàn chỉnh, giống như nhập tất cả các gói. Newbie đây;) Cảm ơn!
Marçal Juan

8
Bạn có thể sử dụng goimports
030

9

Ban đầu đoạn mã này được tìm thấy trên GitHub Gist , nhưng trong khi cố gắng áp dụng khái niệm cho một trong các dự án của mình, tôi nhận ra rằng tôi phải sửa đổi mã chính đáng kể và tôi quyết định kiểm tra các lệnh gọi này bằng cách sử dụng thử nghiệm tích hợp bằng cách sử dụng docker và curl.


8

Nếu bạn muốn kiểm tra chương trình của mình, cách tốt nhất là viết nó có tính đến kiểm tra. Ví dụ: nếu bạn trích xuất vòng lặp bên trong của retrieveTweetshàm thành một thứ như thế này:

func downloadTweets(tweetsUrl string) (*twitterResult, error)

Bạn có thể gọi nó bằng URL của máy chủ thử nghiệm mà bạn đã thiết lập bằng cách sử dụng httptestgói mà không phải lo lắng về chế độ ngủ hoặc các yêu cầu lặp lại.


Tôi có thể mô phỏng một máy chủ không? Tôi nghĩ rằng làm ướt lên một máy chủ thử nghiệm phủ nhận mục đích của kiểm tra, nếu tôi có thể thử ra một máy chủ và phản ứng tôi hy vọng rằng sẽ phù hợp tốt với các thử nghiệm
jwesonga

4
Các httptestgói là cơ sở hạ tầng để thiết lập một máy chủ HTTP nhỏ cho các bài kiểm tra. Bạn có thể triển khai các trình xử lý yêu cầu giống như cách bạn thường làm, sau đó chạy mã của bạn trên máy chủ đó thay vì Twitter.
James Henstridge

@JamesHenstridge cảm ơn bạn, câu trả lời tuyệt vời! Bạn nhận xét ở đây là nhiều thông tin hơn Tuyên bố Tổng quan về các tài liệu chính thức cho net / http / httptest
Rob Kielty
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.