注:本文译自 The awesomeness of the httptest package in Go
Go 有一个很好的 http 包。我之所以能这么说,是因为除了标准库提供的实现之外,我不知道 Go 中有任何其他实现。这对我来说是一个好兆头。
1 | resp, err := http.Get("http://example.com/") |
这个例子来自 go 文档 。
我们来这里是为了阅读有关测试的内容,所以谁关心 http 包本身!重要的是 httptest 包!酷多了。
服务器端
http 包提供了客户端和服务器。服务器由处理程序组成,处理程序接受请求并根据该请求返回响应。
这是它的界接口定义:
1 | type Handler interface { |
正如您所看到的,它根据收到的请求通过 ResponseWriter
来返回响应。在这个过程中,它可能读数据库、调用第三方服务,但最终,它会将结果写到一个响应。
这意味着模拟所有依赖项将获得正确的场景,我们使用 ResponseWriter
来确定处理程序是否满足了我们的要求。
httptest
包提供了 ResponseWriter
的 替身,称为 ResponseRecorder
。我们可以将它传递给处理程序并检查它执行后的样子:
1 | handler := func(w http.ResponseWriter, r *http.Request) { |
这个处理程序非常简单,它只是操作响应主体。如果您的处理程序更复杂并且具有依赖项,您还必须确保替换它们,注入适当的处理程序。
客户端
Go http 包还提供了一个 http 客户端,您可以使用它与 http 服务器交互。http 客户端本身是无用的,但它是对通过 HTTP 获取的信息进行所有操作和转换的入口点。随着微服务的激增,这是一种非常普遍的情况。
工作流程很好理解,您有一个可以与之交互的 HTTP 后端,您可以从那里获取数据,然后使用业务逻辑来操作它们。在测试时,您可以做的就是模拟 http 后端以返回您想要的内容,测试您的业务逻辑是否根据从 HTTP 服务器获得的输入执行其应该执行的操作。
在我们的第一个示例中,处理程序是我们测试的主题,但情况不再是这样,这次我们测试客户端,因此我们必须模仿处理程序才能获得我们期望返回的内容:
1 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
正如您所看到的,我们正在通过 httptest 创建一个新的 HTTP 服务器。它接受一个处理程序,该处理程序的目标是返回我们想要获取代码的内容。理论上,它应该只使用 ResponseWriter
来编写我们期望的响应。
服务器有一堆方法,你要找的就是 URL
方法。因为我们可以将它传递给 http.Client
,我们将使用它作为函数的模拟:
1 | res, err := http.Get(ts.URL) |
就是这样,正如您所看到的,ts.URL
将 http.Client
指向我们创建的模拟服务器。
结论
我经常使用 httptest 包,因为我可以遵循他们的文档来模拟他们的服务器,并且在我对自己编写的代码充满信心之前,我不需要接触他们。
我的建议是测试您的客户端代码是否存在边缘情况,因为 httptest.Server
使您可以灵活地编写您可以想到的任何响应:您可以模仿授权响应来查看代码如何处理它,或者返回空正文或添加速率限制。