golang web开发 Handler测试利器httptest_kingeasternsun的博客-程序员宝宝

技术标签: Golang你所不知道的技巧  Go  

test是golang语言的一部分,golang提供了非常强大的测试方法。单元测试,压力测试可以参见 golang 1.7之后高级测试方法之子测试,子基准测试(subtest sub-benchmarks)

我们用go开发一个Web Server后,打算单元测试写的handler函数,在不知道httptest之前,使用比较笨的方法
就是编译运行该Web Server后,再用go编写一个客户端程序向该Web Server对应的route发送数据然后解析
返回的数据。这个方法测试时非常麻烦,使用httptest来测试的话就非常简单,可以和testing测试一起使用。

httptest基本使用方法

假设在server中handler已经写好

http.HandleFunc("/health-check", HealthCheckHandler)

func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
    // A very simple health check.
    w.WriteHeader(http.StatusOK)
    w.Header().Set("Content-Type", "application/json")

    // In the future we could report back on the status of our DB, or our cache 
    // (e.g. Redis) by performing a simple PING, and include them in the response.
    io.WriteString(w, `{"alive": true}`)
}

测试如下:

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

func TestHealthCheckHandler(t *testing.T) {
    //创建一个请求
    req, err := http.NewRequest("GET", "/health-check", nil)
    if err != nil {
        t.Fatal(err)
    }

    // 我们创建一个 ResponseRecorder (which satisfies http.ResponseWriter)来记录响应
    rr := httptest.NewRecorder()

    //直接使用HealthCheckHandler,传入参数rr,req
    HealthCheckHandler(rr, req)

    // 检测返回的状态码
    if status := rr.Code; status != http.StatusOK {
    
        t.Errorf("handler returned wrong status code: got %v want %v",
            status, http.StatusOK)
    }

    // 检测返回的数据
    expected := `{
   "alive": true}`
    if rr.Body.String() != expected {
        t.Errorf("handler returned unexpected body: got %v want %v",
            rr.Body.String(), expected)
    }
}

然后就可以使用run test来执行测试.

如果Web Server有操作数据库的行为,需要在init函数中进行数据库的连接。

参考官方文档中的样例编写的另外一个测试代码:

func TestHealthCheckHandler2(t *testing.T) {
    reqData := struct {
        Info string `json:"info"`
    }{Info: "P123451"}

    reqBody, _ := json.Marshal(reqData)
    fmt.Println("input:", string(reqBody))
    req := httptest.NewRequest(
        http.MethodPost,
        "/health-check",
        bytes.NewReader(reqBody),
    )

    req.Header.Set("userid", "wdt")
    req.Header.Set("commpay", "brk")

    rr := httptest.NewRecorder()
    HealthCheckHandler(rr, req)

    result := rr.Result()

    body, _ := ioutil.ReadAll(result.Body)
    fmt.Println(string(body))

    if result.StatusCode != http.StatusOK {
        t.Errorf("expected status 200,",result.StatusCode)
    }
}

注意不同的地方
- http.NewRequest替换为httptest.NewRequest。
- httptest.NewRequest的第三个参数可以用来传递body数据,必须实现io.Reader接口。
- httptest.NewRequest不会返回error,无需进行err!=nil检查。
- 解析响应时没直接使用ResponseRecorder,而是调用了Result函数。

结合context使用

func TestGetProjectsHandler(t *testing.T) {
    req, err := http.NewRequest("GET", "/api/users", nil)
    if err != nil {
        t.Fatal(err)
    }

    rr := httptest.NewRecorder()
    // e.g. func GetUsersHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
    handler := http.HandlerFunc(GetUsersHandler)

    // Populate the request's context with our test data.
    ctx := req.Context()
    ctx = context.WithValue(ctx, "app.auth.token", "abc123")
    ctx = context.WithValue(ctx, "app.user",
        &YourUser{ID: "qejqjq", Email: "[email protected]"})

    // Add our context to the request: note that WithContext returns a copy of
    // the request, which we must assign.
    req = req.WithContext(ctx)
    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)
    }
}

参考

httptest doc
Testing Your (HTTP) Handlers in Go

推荐干货满满的技术专栏
这里写图片描述

这里写图片描述[toc]

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/KingEasternSun/article/details/78248101

智能推荐

【三层架构】三层总结(代码型)_Dongle_Kevin的博客-程序员宝宝

本文主要描述以登陆为例,实现三层架构模型的代码示范。

精彩回顾 | Boolan主办2021全球机器学习技术大会北京圆满落幕_Boolan博览的博客-程序员宝宝

4月16-17日,由Boolan主办的2021全球机器学习技术大会在北京金茂威斯汀大饭店盛大召开!本次大会不仅有深度学习的元老级教父、LSTM之父、 IDSIA AI Lab主任 Jürgen Schmidhuber,Google大脑高级研究科学家Lukasz Kaiser,计算机视觉先驱OpenCV创始人Gary Bradski发表主题演讲,同时有来自腾讯、阿里、华为、字节跳动、快手、eBay、AirBnB等近40位机器学习领域一线专家大咖实力开讲,与来自电商、在线娱乐、金融、汽车、智能制造、通信、工业互

嵌入式项目开发_W----D的博客-程序员宝宝_嵌入式开发项目

前言就嵌入式来说,51单片机、stm32单片机、 Cortex-A微处理器,都可以用来开发嵌入式项目。为个人深入了解学习与对比,进而写下此篇笔记。1.开发环境开发不同的芯片,首先应当有具体的硬件环境,其次是搭建配置软件环境。软件环境搭建记录---->传送门2.51、stm32、s5pv210对比1.横向对比51单片机-Cortex-M-ARM Cortex-A8内核处理器具体:STC15F2K60S2 兼容8051内核 Flash:60K SRAM:2K EEPROM:1K 内部时

mongodb 多表联合查询_枪枪枪的博客-程序员宝宝_mongodb 联合查询

db.app_examine_interception.aggregate( [ { $match:{ $or:[{'error_no':'105'},{'error_no':'103'}] } }, { $lookup:{ from:"project", localField:'publis.

随便推点

客户端机器使用Toad连接远程机器的oracle数据库注意事项_jiangzh1982的博客-程序员宝宝

首先说明下本机环境:我本机没有装Oracle的任何软件,下载了一个Toad想要使用它连接到服务器上的一个Oracle的数据库。 1.这种情况在我的机器上必须要安装Oracle的客户端,可以上官方网站上下载instantclient,请选择你要的版本 2.下载之后将该压缩包的文件解压到D:\ORA10 3.在D:\ORA10下建立network/admin两个空的文...

3.NDK Android jni开发 C语言中打印log debug模式下 (相机图片美化)_深南大盗的博客-程序员宝宝

日志打印:对于很多Android开发人员来说,Android的标准日志打印已经使用的非常习惯,如果在调试C/C++时使用的是printf或者cout这种方式打印日志,那查找起来会非常不舒服,为了使自己舒服起来,还是有必要使用android标准的日志方式打印日志的。先看一下效果:引入导入log头文件在你使用的 .c/ .cpp 文件中导入 log.h 头文件#include<android/log.h>#include <android/lo...

纯CSS设置Checkbox复选框控件的样式_shelleyHLX的博客-程序员宝宝_checkbox css

下面是纯CSS设置Checkbox复选框控件的五种简单样式,有兴趣的可以进行改动将其变成自己想要的样式。首先,需要添加一段CSS隐藏所有的Checkbox复选框,下面我们会改变它的外观。要做到点需要添加一段代码到你的CSS文件中。隐藏掉所有的Checkbox复选框后,我们需要添加一个label HTML元素,我们都知道,当点击的有for属性的label标签时,对应的Checkbox复选框会被选中。这意味着,我们可以通过label的点击事件来处理我们的Checkbox复选框。样式一

ObjectARX 2018 + AutoCAD2018 + VS2018 C# 创建第一个 Hello word程序_偷偷玩两下的博客-程序员宝宝_objectarx2018

采用ObjectARX 2018 与 AutoCAD2018 与 C# 创建第一个hello word程序。Hello word 程序基本创建过程如下:0. 软件安装:软件版本:vs2018、Autodesk_ObjectARX SDK 2018、AutoCADNetWizards 2018、ObjectARXWizards 2018 。在vs2018中安装Autode...

Jenkins集成RobotFramework自动化测试_ElenaYu的博客-程序员宝宝

注意点以及环境准备1.Jenkins的机器上需要安装有RobotFramework的环境 2.需要有RobotFramework脚本运行依赖的库源码管理构建触发器构建 注意:这里的日志保存路径和构建后的output路径都建议修改为Jenkins的工作路径,两者需要保持一致。构建后操作test result配置邮件配置...

推荐文章

热门文章

相关标签