Open lzh2nix opened 4 years ago
原文: https://markjberger.com/testing-web-apps-in-golang/
这里作者举了一个比较简单的例子,使用了最原始的stdlib http
func homeHandler(db AppDatabase) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there, I love %s!", db.GetBacon())
})
}
其中对Database的依赖放到参数中(依赖注入),然后对其进行简单的测试:
function TestHome(t *testing.T) {
mockDb := MockDb{}
homeHandle := homeHandler(mockDb)
req, _ := http.NewRequest("GET", "", nil)
w := httptest.NewRecorder()
homeHandle.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Errorf("Home page didn't return %v", http.StatusOK)
}
}
再进一步抽象:
type HandleTester func(
method string,
params url.Values,
) *httptest.ResponseRecorder
// Given the current test runner and an http.Handler, generate a
// HandleTester which will test its given input against the
// handler.
func GenerateHandleTester(
t *testing.T,
handleFunc http.Handler,
) HandleTester {
// Given a method type ("GET", "POST", etc) and
// parameters, serve the response against the handler and
// return the ResponseRecorder.
return func(
method string,
params url.Values,
) *httptest.ResponseRecorder {
req, err := http.NewRequest(
method,
"",
strings.NewReader(params.Encode()),
)
if err != nil {
t.Errorf("%v", err)
}
req.Header.Set(
"Content-Type",
"application/x-www-form-urlencoded; param=value",
)
w := httptest.NewRecorder()
handleFunc.ServeHTTP(w, req)
return w
}
}
function TestHome(t *testing.T) {
mockDb := MockDb{}
homeHandle := homeHandler(mockDb)
test := GenerateHandleTester(t, homeHandle)
w := test("GET", url.Values{})
if w.Code != http.StatusOK {
t.Errorf("Home page didn't return %v", http.StatusOK)
}
}
但是实际项目中可能没有直接使用原始的http,每个公司都有对其的一些简单封装,我们的一般做法的是每个服务都写一个client, 然后通过client去测试每个api的行为(httptest.NewServer)。这样从路由到权限一路全部能够check到。
原文: https://tutorialedge.net/golang/intro-testing-in-go/
简单介绍了一下golang原生的test, 不过go的原生test已经很强大了。
go test // 跑测试
go test -cover // 输出覆盖率信息
go test -coverprofile=coverage.out // 导出覆盖率信息
go tool cover -html=coverage.out // 查看覆盖情况
原文: https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742
var fibTests = []struct {
n int // input
expected int // expected result
}{
{1, 1},
{2, 1},
{3, 2},
{4, 3},
{5, 5},
{6, 8},
{7, 13},
}
基本和之前几篇文章的思路相同
原文: https://medium.com/@xoen/go-testing-technique-testing-json-http-requests-76d9ce0e11f#.95p1r8n16
http 相关的测试使用httptest.NewServer 都是常规操作。怎么去写测试这块我觉得还是直接参考比较成熟的项目就ok了,然后模仿其中的写法。
关于json我们都是marshal/unmarshal之后按照常规的对象来看下,这里作者提供了另外一种思路
reqJson, err := simplejson.NewFromReader(r.Body)
这样不用特意的去解析整个struct, 需要的字段直接通过
lifeMeaning := reqJson.GetPath("meta", "lifeMeaning").MustInt()
这种方式提取。
快速构建json 对象:
payload := fmt.Sprintf(`
{
"meta": {
"lifeMeaning": %d
},
"data": {
" “message”: "%s"
}
}`, LIFE_MEANING, msg)
原文: https://blog.questionable.services/article/testing-http-handlers-go/
这里介绍了http相关的一些测试方法
func TestHealthCheckHandler(t *testing.T) {
// Create a request to pass to our handler. We don't have any query parameters for now, so we'll
// pass 'nil' as the third parameter.
req, err := http.NewRequest("GET", "/health-check", nil)
if err != nil {
t.Fatal(err)
}
// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
rr := httptest.NewRecorder()
handler := http.HandlerFunc(HealthCheckHandler) // 这里是需要测试的方法
// Our handlers satisfy http.Handler, so we can call their ServeHTTP method
// directly and pass in our Request and ResponseRecorder.
handler.ServeHTTP(rr, req)
// Check the status code is what we expect.
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}
// Check the response body is what we expect.
expected := `{"alive": true}`
if rr.Body.String() != expected {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
}
}
func TestPopulateContext(t *testing.T) {
req, err := http.NewRequest("GET", "/api/users", nil)
if err != nil {
t.Fatal(err)
}
testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 这个handler会在中间件之后调用,所以这里可以测试中间件的行为
if val, ok := r.Context().Value("app.req.id").(string); !ok {
t.Errorf("app.req.id not in request context: got %q", val)
}
})
rr := httptest.NewRecorder()
// func RequestIDMiddleware(h http.Handler) http.Handler
// Stores an "app.req.id" in the request context.
handler := RequestIDMiddleware(testHandler)
handler.ServeHTTP(rr, req)
}
使用inerface来对数据库的抽象,而不依赖具体的数据库。
这一点确实太难了,比如你项目中依赖的是mongoDB 你怎么在测试mock mongo相关的接口就是一个很大的问题。
原文: https://deadbeef.me/2018/05/go-test
主要讲一些go test中的小技巧
go list ./... | grep -v 'testhelper'
跳过某些package原文: https://splice.com/blog/lesser-known-features-go-test/
func TestCountMallocs(t *testing.T) {
if testing.Short() {
t.Skip("skipping malloc count in short mode")
}
// rest of test...
}
目录
Testing Web Apps in Go(2020.08.15) An Introduction to Testing in Go(2020.08.16) 5 simple tips and tricks for writing unit tests in(2020.08.17) Interfaces and Composition for Effective Unit Testing in Golang(2020.08.17) Go Testing Technique: Testing JSON HTTP Requests(2020.08.17) Testing Your (HTTP) Handlers in Go(2020.08.18) Go test your tests in Go with go test(2020.08.18) Lesser-Known Features of Go Test(2020.08.18)