英文:
How to test http request handlers
问题
我有一组请求处理程序,就像下面这个例子:
func GetProductsHandler(w http.ResponseWriter, req *http.Request) {
defer req.Body.Close()
products := db.GetProducts()
// ...
// 将产品作为 JSON 数组返回
}
我该如何正确地测试它们?我应该向函数发送模拟的 ResponseWriter 和 Request 对象,并查看结果吗?
在 Go 中,是否有工具可以模拟请求和响应对象,以简化测试过程,而无需在测试之前启动服务器?
英文:
I have a set of requests handlers like the one below:
func GetProductsHandler(w http.ResponseWriter, req *http.Request) {
defer req.Body.Close()
products := db.GetProducts()
// ...
// return products as JSON array
}
How do I test them the right way? Should I send mock ResponseWriter and Request objects to the function and see the results?
Are there tools to mock request and response objects in Go to simplify the process without having to start server before testing?
答案1
得分: 8
Go提供了一个用于测试处理程序的模拟写入器。标准库文档提供了一个示例:
package main
import (
"fmt"
"net/http"
"net/http/httptest"
)
func main() {
handler := func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "something failed", http.StatusInternalServerError)
}
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
w := httptest.NewRecorder()
handler(w, req)
fmt.Printf("%d - %s", w.Code, w.Body.String())
}
我认为全局依赖(db
)会给清晰的单元测试带来麻烦。使用Go,你的测试可以重新分配一个值,掩盖全局的db
值。
另一种策略(我更喜欢的)是将处理程序封装在一个结构体中,该结构体具有一个db
属性。
type Handlers struct {
db DB_INTERFACE
}
func (hs *Handlers) GetProductsHandler(w http.ResponseWriter, req *http.Request) {...}
这样,你的测试可以使用一个存根db
对象实例化一个Handlers
,从而允许你创建无IO的单元测试。
英文:
Go provides a mock writer for use in testing handlers. The standard library documentation provides an example:
package main
import (
"fmt"
"net/http"
"net/http/httptest"
)
func main() {
handler := func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "something failed", http.StatusInternalServerError)
}
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
w := httptest.NewRecorder()
handler(w, req)
fmt.Printf("%d - %s", w.Code, w.Body.String())
}
I think having a global dependency (db
) throws a wrench into clean unit testing. Using go your test could reassign a value, masking, the global value of db
.
Another strategy (my preferred) is to package your handler in a struct, which has a db
attribute..
type Handlers struct {
db DB_INTERFACE
}
func (hs *Handlers) GetProductsHandler(w http.ResponseWriter, req *http.Request) {...}
This way your test can instantiate a Handlers
with a stub db
object which will allow you to create IO free unit tests.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论