go的单元测试驱动开发之web开发的单元测试

程序员开发过程中,最头疼的是bug,那么 有一种方法是单元测试,可以尽可能的减少上线出现故障的概率,
什么是 Gin
Gin 是一个用 Golang 写的 http web 框架。

这是来自 Gin Github 上的描述。

开发环境
GoLand 2019.2 EAP
GoLang 1.11.5
采用 Go Modules 进行管理
快速入门
用 GoLand 新建项目的时候,我们选择 Go Modules(vgo) ,填写我们的项目地址和项目名称,我们命名为 GinHello 。
在这里插入图片描述

新建项目
点击 Create ,此时 Goland 为我们生成了项目目录,Go 项目的目录永远是那么的简单,比 Java 的 Maven 或者 Gradle 生成的项目目录简单多了。

GinHello
|
|-go.mod
对,就是一个文件 ,一个 Go module 文件。go mod 是 Go 官方引入的一个依赖管理工具。

添加依赖
通过 go mod 文件进行依赖的。

require github.com/gin-gonic/gin v1.4.0

我们把上面的依赖进行添加到 go module 中, goLand 会自动帮我们进行依赖的下载和管理。

Hello Gin
当完成依赖的添加,就可以开始写代码了。

新建一个 main.go 文件。

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    router.Run()
}

Gin 只需要两行代码就可以把我们的服务跑起来。

我们只要点击运行,项目便会启动一个 8080 端口,打开浏览器 localhost:8080 我们便可以看到页面上提示出 404 page not found ,这是因为我们的根路由上并没有返回任何结果。同时我们可以在控制台上看到一些打印信息,其中就包括我们刚刚访问根路由的端口。

产生接口
项目已经启动了,那么如何返回一个接口呢?

通过 router 的 Handle 进行配置我们返回的参数。

// 省略代码
// 添加 Get 请求路由
r.GET("/", func(context *gin.Context) {
context.String(http.StatusOK, “hello gin”)
})
// 省略代码

此时我们重启项目,重新访问页面 localhost:808,此刻的页面上已经显示了 hello gin。

同样,我们还可以进行 POST,PUT,DELETE等请求方式。

单元测试
单元测试是项目不能缺少的模块,也是保障项目可以正常运行的重要依赖。下面就对 Gin 进行单元测试。

为了方便单元测试,我们首先要对我们的项目进行一下抽取。

新建立一个文件夹叫做 initRouter

建立 go 文件 initRouter.go

package initRouter

import (
    "github.com/gin-gonic/gin"
    "net/http"
)

func SetupRouter() *gin.Engine {
    router := gin.Default()
    // 添加 Get 请求路由
    router.GET("/", func(context *gin.Context) {
        context.String(http.StatusOK, "hello gin")
    })
    return router
}

同时修改 main.go

package main

import (
    "GinHello/initRouter"
)

func main() {
    router := initRouter.SetupRouter()
    _ = router.Run()
}

完成了项目测试的初步建立。

建立 test 目录, golang 的单元测试都是以 _test 结尾,建立 index_test.go 文件。

package test

import (
    "GinHello/initRouter"
    "github.com/stretchr/testify/assert"
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestIndexGetRouter(t *testing.T) {
    router := initRouter.SetupRouter()
    w := httptest.NewRecorder()
    req, _ := http.NewRequest(http.MethodGet, "/", nil)
    router.ServeHTTP(w, req)
    assert.Equal(t, http.StatusOK, w.Code)
    assert.Equal(t, "hello gin", w.Body.String())
}

通过 assert 进行断言,来判断返回状态码和返回值是否与代码中的值一致。

此时的项目目录为:

GinHello
|
|-initRouter
| |-initRouter.go
|
|-test
| |-index_test.go
|
|-main.go
|-go.mod
|-go.sum
运行单元测试,控制台打印出单元测试结果。

— PASS: TestIndexGetRouter (0.02s)
PASS

总结
通过简单的搭建一个 Gin 项目,可以看到 Go 语言搭建一个 Http 服务器很简单,也很方便,零配置即可完成项目并运行起来。

作者:一个正在成为码农的人
链接:https://www.jianshu.com/p/39e4f683c43b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

我们也可以测试api接口

比如
book.go

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

func SetupRouter() *gin.Engine {
	router := gin.Default()
	// 添加 Get 请求路由
	router.GET("/", Hello)
	router.GET("/test", Book2)
	router.POST("/post", Book3)
	return router
}

func Hello(context *gin.Context) {
	context.String(http.StatusOK, "hello gin")
}

func main() {
	router := SetupRouter()
	_ = router.Run("0.0.0.0:8080")
}

func Book2(c *gin.Context) {
	c.JSON(200,
		gin.H{"message": time.Now(), "status": 1, "result": nil})
}

type bo struct {
	Name string `json:"name" binding:"required" `
	Num  string `json:"num"`
}

func Book3(c *gin.Context) {
	var data bo
	err := c.ShouldBind(&data)
	if err != nil {
		fmt.Println(err)
		c.JSON(200, gin.H{"message": err, "status": -1, "result": nil})
		return
	}
	c.JSON(200, gin.H{"message": "Success", "status": 1, "result": data})
}

那么对应的单元测试为
book_test.go

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/stretchr/testify/assert"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestHello(t *testing.T) {
	router := SetupRouter()
	w := httptest.NewRecorder()
	req, _ := http.NewRequest(http.MethodGet, "/", nil)
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
	assert.Equal(t, "hello gin", w.Body.String())
}
func TestBook2(t *testing.T) {
	router := SetupRouter()
	w := httptest.NewRecorder()
	req, _ := http.NewRequest(http.MethodGet, "/test", nil)
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
	data := make(map[string]interface{})
	err := json.Unmarshal(w.Body.Bytes(), &data)
	if err != nil {
		fmt.Println(err)
	}
	assert.Equal(t, data["status"], float64(1))
}

func TestBook3(t *testing.T) {
	router := SetupRouter()
	w := httptest.NewRecorder()
	bodyMap := make(map[string]interface{})
	bodyMap["name"] = "test"
	bodyMap["num"] = "1"
	byteData, _ := json.Marshal(bodyMap)
	body := bytes.NewReader(byteData)
	req, _ := http.NewRequest(http.MethodPost, "/post", body)
	req.Header.Set("Content-Type", "application/json")
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
	data := make(map[string]interface{})
	err := json.Unmarshal(w.Body.Bytes(), &data)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("data", data)
	assert.Equal(t, data["status"], float64(1))
}


测试输出的效果为

[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /                         --> learn/gin/test/main.Hello (3 handlers)
[GIN-debug] GET    /test                     --> learn/gin/test/main.Book2 (3 handlers)
[GIN-debug] POST   /post                     --> learn/gin/test/main.Book3 (3 handlers)
[GIN] 2020/05/03 - 21:51:59 |?[97;42m 200 ?[0m|            0s |                 |?[97;44m GET     ?[0m /
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /                         --> learn/gin/test/main.Hello (3 handlers)
[GIN-debug] GET    /test                     --> learn/gin/test/main.Book2 (3 handlers)
[GIN-debug] POST   /post                     --> learn/gin/test/main.Book3 (3 handlers)
[GIN] 2020/05/03 - 21:51:59 |?[97;42m 200 ?[0m|       998.4µs |                 |?[97;44m GET     ?[0m /test
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /                         --> learn/gin/test/main.Hello (3 handlers)
[GIN-debug] GET    /test                     --> learn/gin/test/main.Book2 (3 handlers)
[GIN-debug] POST   /post                     --> learn/gin/test/main.Book3 (3 handlers)
[GIN] 2020/05/03 - 21:51:59 |?[97;42m 200 ?[0m|      1.0001ms |                 |?[97;46m POST    ?[0m /post
data map[message:Success result:map[name:test num:1] status:1]
PASS
ok      learn/gin/test/main     5.210s



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值