迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > Go >

Golang httptest 的示例

作者:迹忆客 最近更新:2023/01/17 浏览次数:

当我第一次了解到它的 HTTP 测试包时,Go (Golang) 给我留下了深刻的印象。 在其他编程语言中,我习惯于做很多测试 HTTP 服务器的工作。 在 Go (Golang) 中,情况并非如此。 有一个很棒的测试包,可以从标准库中立即使用,而且非常容易理解。 让我们看看如何使用 httptest 包并为我们的 Go http 服务构建更好的端到端和 http 测试。

httptest 包背后的想法是很容易模拟 HTTP 服务器或模拟响应编写器以提供给我们的服务器处理程序。 这使得测试 http 服务器和客户端变得非常容易。

在本文中,我们将探索 httptest 包可以发挥作用的两个特定场景

  • 测试 Go http 服务器处理程序
  • 测试 Go http 客户端

测试 Go HTTP 服务器处理程序

让我们看一个 Go 中的 http 服务器的例子。 下面你可以找到一个服务器的例子,它接受一个词并返回它的大写版本。

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/url"
    "strings"
)

// Req: http://localhost:1234/upper?word=abc
// Res: ABC
func upperCaseHandler(w http.ResponseWriter, r *http.Request) {
    query, err := url.ParseQuery(r.URL.RawQuery)
    if err != nil {
        w.WriteHeader(http.StatusBadRequest)
        fmt.Fprintf(w, "invalid request")
        return
    }
    word := query.Get("word")
    if len(word) == 0 {
        w.WriteHeader(http.StatusBadRequest)
        fmt.Fprintf(w, "missing word")
        return
    }
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, strings.ToUpper(word))
}

func main() {
    http.HandleFunc("/upper", upperCaseHandler)
    log.Fatal(http.ListenAndServe(":1234", nil))
}

在这种情况下,我们要测试用于我们的 Go 服务器的 upperCaseHandler 逻辑。 我们需要两件事来测试:

可以使用 httptest.NewRequest 导出函数创建的 http.Request

NewRequest 返回一个新的传入服务器 Request,适合传递给一个 http.Handler 进行测试。

可以使用返回 httptest.ResponseRecorderhttptest.NewRecorder 类型创建的 http.ResponseWriter

ResponseRecorderhttp.ResponseWriter 的一个实现,它记录它的变化以供以后在测试中检查。


使用 httptest.ResponseRecorder

httptest.ResponseRecorderhttp.ResponseWriter 的实现,可用于传递到我们的服务器处理程序,记录处理程序将写入响应的所有数据并返回之后写入的数据。 让我们看看它在下面的示例测试中是如何工作的。

package main

import (
    "io/ioutil"
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestUpperCaseHandler(t *testing.T) {
    req := httptest.NewRequest(http.MethodGet, "/upper?word=abc", nil)
    w := httptest.NewRecorder()
    upperCaseHandler(w, req)
    res := w.Result()
    defer res.Body.Close()
    data, err := ioutil.ReadAll(res.Body)
    if err != nil {
        t.Errorf("expected error to be nil got %v", err)
    }
    if string(data) != "ABC" {
        t.Errorf("expected ABC got %v", string(data))
    }
}

这将允许我们通过检查 Result 方法返回的 ResponseRecorder 输出来测试处理程序响应

func (rw *ResponseRecorder) Result() *http.Response

结果返回处理程序生成的响应。 返回的 Response 将至少填充其 StatusCode、Header、Body 和可选的 Trailer。 将来可能会填充更多字段,因此调用者不应在测试中使用 DeepEqual 结果。


测试 Go HTTP 客户端

测试 Go 服务器处理程序相对容易,尤其是当您只想测试处理程序逻辑时。 您只需要在测试中模拟 http.ResponseWriterhttp.Request 对象。 但是,当使用 Go http 客户端时,事情会稍微复杂一些。 原因是有时模拟或复制整个服务器并不那么容易。 让我们看看下面的例子。

package main

import (
    "io/ioutil"
    "net/http"

    "github.com/pkg/errors"
)

type Client struct {
    url string
}

func NewClient(url string) Client {
    return Client{url}
}

func (c Client) UpperCase(word string) (string, error) {
    res, err := http.Get(c.url + "/upper?word=" + word)
    if err != nil {
        return "", errors.Wrap(err, "unable to complete Get request")
    }
    defer res.Body.Close()
    out, err := ioutil.ReadAll(res.Body)
    if err != nil {
        return "", errors.Wrap(err, "unable to read response data")
    }

    return string(out), nil
}

我们的 Go 客户端需要一个代表远程服务器基本 URL 的基本 URL。 然后它使用给定的输入词调用方法 /upper 并将结果作为字符串返回给调用者,或者在请求未成功的情况下返回错误。 为了测试这段代码,我们需要模拟整个服务器逻辑,或者至少模拟负责给定请求路径的逻辑,比如我们的例子中的 /upper 路径。 使用 httptest 包,我们可以通过初始化一个监听环回接口的本地服务器来模拟整个服务器,该接口将返回我们想要的任何东西。


使用 httptest.Server

我们要使用的类型是 httptest.Server 类型,通过调用 httptest.NewServer 函数。

服务器是一个 HTTP 服务器,在本地环回接口上侦听系统选择的端口,用于端到端 HTTP 测试。

func NewServer(handler http.Handler) *Server

NewServer 启动并返回一个新的 Server。 调用者应在完成后调用 Close 以将其关闭。

让我们看看我们如何在下面的例子中做到这一点。

package main

import (
    "fmt"
    "net/http"
    "net/http/httptest"
    "strings"
    "testing"
)

func TestClientUpperCase(t *testing.T) {
    expected := "dummy data"
    svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, expected)
    }))
    defer svr.Close()
    c := NewClient(svr.URL)
    res, err := c.UpperCase("anything")
    if err != nil {
        t.Errorf("expected err to be nil got %v", err)
    }
    // res: expected\r\n
    // due to the http protocol cleanup response
    res = strings.TrimSpace(res)
    if res != expected {
        t.Errorf("expected res to be %s got %s", expected, res)
    }
}

在上面的示例中,我们刚刚使用 httptest.NewServer 函数创建了一个新的模拟服务器,为其分配了一个始终返回相同数据的自定义模拟处理程序,并将服务器 URL 用作我们客户端的服务器 URL。 这允许我们模拟并指示服务器返回我们想要用于测试目的的任何东西。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

Golang 中的零值 Nil

发布时间:2023/04/27 浏览次数:166 分类:Go

本篇文章介绍 nil 在 Golang 中的含义,nil 是 Go 编程语言中的零值,是众所周知且重要的预定义标识符。

Golang 中的 Lambda 表达式

发布时间:2023/04/27 浏览次数:93 分类:Go

本篇文章介绍如何在 Golang 中创建 lambda 表达式。Lambda 表达式似乎不存在于 Golang 中。 函数文字、lambda 函数或闭包是匿名函数的另一个名称。

在 Go 中使用断言

发布时间:2023/04/27 浏览次数:181 分类:Go

本篇文章介绍了 assert 在 GoLang 中的使用。在 Go 语言中使用断言:GoLang 不提供对断言的任何内置支持,但我们可以使用来自 Testify API 的广泛使用的第三方包断言。

Go 中的随机数生成

发布时间:2023/04/27 浏览次数:114 分类:Go

本篇文章介绍如何在 Go 语言中使用随机数生成功能。Go 中的随机数生成 Go 语言为随机数生成功能提供内置支持。 内置包 math 有方法 rand(),用于随机数生成。

GoLang 电子邮件验证器

发布时间:2023/04/27 浏览次数:195 分类:Go

本篇文章介绍如何在 Go 语言中验证电子邮件。电子邮件需要特定格式; 否则,它们将无法工作。

卸载 GoLang

发布时间:2023/04/27 浏览次数:183 分类:Go

本篇文章介绍如何在不同的操作系统上卸载 GoLang。卸载 Go 语言 只需几个简单的步骤即可卸载 GoLang。 这些步骤对于不同的操作系统是不同的。

在 Go 中使用 Electron API 创建 GUI

发布时间:2023/04/27 浏览次数:124 分类:Go

本篇文章介绍如何在 Go 语言中使用 Electron API 创建 GUI。Electron API 或 Astilectron 用于为 GoLang 创建 GUI。

在 GoLang 中安装包

发布时间:2023/04/27 浏览次数:122 分类:Go

使用 Go 语言的 get 命令安装所需的包非常容易。 Go 语言提供了多种命令来执行某些任务,get 就是其中之一。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便