前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言中常见100问题-#88-1 Not using testing utility packages

Go语言中常见100问题-#88-1 Not using testing utility packages

作者头像
数据小冰
发布2022-08-15 15:32:06
2860
发布2022-08-15 15:32:06
举报
文章被收录于专栏:数据小冰
忽视httptest测试工具包

Go语言标准库提供了一些用于测试的工具包,常见的问题是有些开发者不知道这些工具包,并试图重新造轮子或依赖其他不太方便的处理方法。本文将深入研究httptest工具包,它可以帮助我们方便测试HTTP程序.

httptest

httptest包可以辅助我们对HTTP的客户端和服务器程序进行测试,下面学习如何使用httptest进行测试。

首先,来看看编写HTTP服务器程序时,如何使用httptest包辅助我们进行测试。下面的Handler程序执行一些基本操作:设置http header,写入body数据并返回特定的状态码。为了突出核心逻辑,省略了错误处理。

代码语言:javascript
复制
func Handler(w http.ResponseWriter, r *http.Request) {
        w.Header().Add("X-API-VERSION", "1.0")
        b, _ := io.ReadAll(r.Body)
        _, _ = w.Write(append([]byte("hello "), b...))
        w.WriteHeader(http.StatusCreated)
}

HTTP处理程序接收两个参数:*http.Request和http.ResponseWriter,分别表示请求信息和写入响应。httptest包提供了创建这两个参数类型对象的构造方法。可以使用httptest.NewRequest创建一个 *http.Request对象,设置HTTP请求方法(GET/POST/PUT等)、请求的URL和正文body内容。对于响应,可以使用httptest.NewRecorder来记录程序处理程序中发生的变化。下面使用httptest包对上面的Handler进行单元测试,实现代码如下。

代码语言:javascript
复制
func TestHandler(t *testing.T) {
        req := httptest.NewRequest(http.MethodGet, "http://localhost",
                strings.NewReader("foo"))
        w := httptest.NewRecorder()
        Handler(w, req)

        if got := w.Result().Header.Get("X-API-VERSION"); got != "1.0" {
                t.Errorf("api version: expected 1.0, got %s", got)
        }

        body, _ := ioutil.ReadAll(w.Body)
        if got := string(body); got != "hello foo" {
                t.Errorf("body: expected hello foo, got %s", got)
        }

        if http.StatusOK != w.Result().StatusCode {
                t.FailNow()
        }
}

使用httptest测试处理程序不会测试传输层,测试的重点是业务逻辑处理,直接使用请求和记录响应的方式调用处理程序,即在本地模拟整个业务处理,不关心网络传输部分。然后,获取记录响应中的内容,判断验证header、正文和状态码等内容是否正确。

下面看看如何使用httptest包辅助我们对客户端程序进行单元测试。先来编写一个 HTTP 客户端程序,该程序请求获取从一个坐标点移动到另一个坐标点的所需要的时间。实现逻辑就是对提供的url发起HTTP POST请求,然后解析返回的内容,返回所用时间。

代码语言:javascript
复制
func (c DurationClient) GetDuration(url string,
        lat1, lng1, lat2, lng2 float64) (
        time.Duration, error) {
        resp, err := c.client.Post(
                url, "application/json",
                buildRequestBody(lat1, lng1, lat2, lng2),
        )
        if err != nil {
                return 0, err
        }

        return parseResponseBody(resp.Body)
}

怎么对上面的函数进行单元测试呢?一种处理方法是使用Docker启动一个模拟的服务器,返回预先注册的响应,但是这种方法比较笨重,执行起来麻烦。另一种处理方法是使用http.NewServer基于提供的处理程序创建本地HTTP服务器,然后调用GetDuration并对返回的结果进行断言。像下面这样,通过httptest.NewServer创建了一个返回持续时间为314秒的静态处理程序的服务器,在调用GetDuration时,传入本地服务器的URL(srv.URL), 将客户端请求与预定的本地处理程序关联起来,返回预定程序的返回值。

代码语言:javascript
复制
func TestDurationClientGet(t *testing.T) {
        srv := httptest.NewServer(
                http.HandlerFunc(
                        func(w http.ResponseWriter, r *http.Request) {
                                _, _ = w.Write([]byte(`{"duration": 314}`))
                        },
                ),
        )
        defer srv.Close()

        client := NewDurationClient()
        duration, err :=
                client.GetDuration(srv.URL, 51.551261, -0.1221146, 51.57, -0.13)
        if err != nil {
                t.Fatal(err)
        }

        if duration != 314*time.Second {
                t.Errorf("expected 314 seconds, got %v", duration)
        }
}

除了使用http.NewServer创建普通的服务器外,还可以使用http.NewTLSServer创建带有TLS的服务器,以及使用httptest.NewUnstartedServer 创建一个未启动的服务器,以便我们可以延迟启动它。

httptest对我们测试HTTP应用程序能够提供非常大的帮助,无论是编写服务器还是客户端程序,它都可以帮助我们进行高效的测试,所以在测试HTTP程序时,不要忽视httptest包。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-08-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据小冰 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 忽视httptest测试工具包
    • httptest
    相关产品与服务
    SSL 证书
    腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档