對beego的控制器函式進行單測

flybywind發表於2019-02-16

根據astaxie大神的意見,在beego上對controller做單測比較困難,他的建議就是把所有邏輯都拆分出來,放到model中。然後對model中的public函式進行測試。

但是這就會多很多封裝,而且,有些時候對controller的測試可能是繞不開的。

其實對controller進行單測也不是那麼麻煩,重點就是把http需要的RequestResponseWriter需要的資料都構造出來即可。

下面是我的做法?重點看程式碼和註釋吧。很多程式碼是self-explanation

package test

import (
    "github.com/astaxie/beego"
    "github.com/astaxie/beego/context"
    "github.com/astaxie/beego/session"
    "net/http"
    "net/url"
    "reflect"
    "testing"
    "youApp/controllers"
)

func prepareController(c *beego.Controller) {
    c.Ctx = &context.Context{
        Request:        &http.Request{URL: &url.URL{Scheme: "http", Host: "localhost", Path: "/"}},
        ResponseWriter: &fakeResponseWriter{},
    }
    c.Ctx.Output = &context.BeegoOutput{Context: c.Ctx}
    c.Ctx.Input = &context.BeegoInput{Request: c.Ctx.Request}
    
    globalSessions, _ := session.NewManager("memory", `{"cookieName":"gosessionid","gclifetime":10}`)
    c.Ctx.Request.Header = http.Header{}
    c.Ctx.Request.AddCookie(&http.Cookie{Name: "gosessionid", Value: "test"})
    c.CruSession = globalSessions.SessionRegenerateId(c.Ctx.ResponseWriter, c.Ctx.Request)
    c.Data = map[interface{}]interface{}{}
}

func TestRecomputeBanlance(t *testing.T) {
    c := &controllers.BanlanceController{}
    prepareController(&(c.Controller))
    // 這是期望使用者在瀏覽器上傳的form表和登陸資訊。
    c.Ctx.Request.Form = url.Values{
        "range": []string{"2016-10-01到2016-10-31"},
        "city": []string{"北京"},
    }
    c.SetSession("login", "123")
    c.Prepare()
    // 這是對應的控制器函式
    c.Recompute()
    // 本例中,資料是通過json傳出來的。
    j := c.Data["json"]
    // 從json中讀取的資料是interface{}型別,需要通過reflect獲取其中的資訊
    mapV := reflect.ValueOf(j)
    errV := mapV.MapIndex(reflect.ValueOf("Error"))
    // 先看看json中有沒有error欄位
    if errV.IsValid() && errV.String() != "" {
        t.Fatal("has error:", errV)
    }
    // 然後讀取ban欄位的內容
    banV := mapV.MapIndex(reflect.ValueOf("ban"))
    if !banV.IsValid() {
        t.Fatal("no output data!")
    } else {
        V := reflect.ValueOf(banV.Interface())
        fnum := V.NumField()
        if fnum < 10 {
            t.Fatal("not ban table format")
        }
        // 讀取關鍵欄位的值進一步判斷
        v1 := V.FieldByName("Value1").Float()
        v2 := V.FieldByName("Value2").Float()
        v3 := V.FieldByName("Value3").Float()
        v4 := V.FieldByName("Value4").Float()
        if !(v1 > 0 &&
            v2 > 0 &&
            v3 > 0 &&
            v4 > 0) {
            t.Fatal("ban table data wrong:", v1, v2, v3, v4)
        }
    }
}

type fakeResponseWriter struct{}

func (f *fakeResponseWriter) Header() http.Header {
    return http.Header{}
}
func (f *fakeResponseWriter) Write(b []byte) (int, error) {
    return 0, nil
}
func (f *fakeResponseWriter) WriteHeader(n int) {}

相關文章