教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Golang单元测试之httptest使用

Golang单元测试之httptest使用

发布时间:2022-02-07   编辑:jiaochengji.com
教程集为您提供Golang单元测试之httptest使用等资源,欢迎您收藏本站,我们将为您提供最新的Golang单元测试之httptest使用资源

现在有一个需求那就是,我们需要使用Golang的net/http包中的http.Get(url)方法去向服务器端请求数据,但是负责服务端的同事并没有将接口实现(可能是同事太忙,把妹,喝酒,扯淡, XO等等)以至于你只知道返回数据的json格式,然而无法请求到真实的数据,但是你的工作进度并不能因为同事而耽误,需要测试你的代码的正确性,那么怎么办?办法就是通过单元测试中的httptest,实现http server,并设置好返回值,那么http.Get(url)的请求就会直接打到单元测试的http server上,同时得到你设置好的返回值,你就可以继续去处理数据,测试你的代码逻辑了。

 

<span style="color:#ff6666;">一、导入</span>

设置一个场景:

需要向服务器端去获取住址为"shanghai"的所有人的信息,请求函数为:

 

<pre class="has"><code class="language-cpp">func GetInfo(api string) ([]Person, error) </code></pre>

这个方法包括:

 

1.向服务端发送get请求获取数据

2.将数据序列化person的信息

3.如果出现错误,返回error

需要测试的内容:

1.需要测试返回值是我们设置的值:

 

<pre class="has"><code class="language-plain">var personResponse = []Person{ { Name : "wahaha", Address : "shanghai", Age : 20, }, { Name : "lebaishi", Address : "shanghai", Age : 10, }, }</code></pre>

2.需要测试GetInfo方法是发送了正确的http请求,及method是否正确,路径是否正确,请求参数是否正确。

 

3.返回状态码是否正确。

 

<span style="color:#ff6666;">二、Golang testing基础</span>

Go提供了一个testing包来写单元测试。假设我们有个文件叫person.go,那么我们的测试文件就需要明明为person_test.go

 

<pre class="has"><code class="language-cpp">package person import ( "testing" ) func TestPublishUnreachable(t *testing.T) { api := "http://localhost:8090" _, err := GetInfo(api) if err != nil { t.Errorf("GetInfo() return an error") } }</code></pre>

注:

 

>测试函数以Test*开头。

>测试函数将*testing.T作为参数,可以在失败的情况下使用Errorf()方法。

>在包内使用go test来运行单元测试。

 

这个单元测试将会失败,因为我们还没有实现GetInfo()方法,下面是person.go文件:

 

<pre class="has"><code class="language-cpp">package person import ( "net/http" "fmt" ) const ( ADDRESS = "shanghai" ) type Person struct { Name string `json:"name"` Address string `json:"address"` Age int `json:"age"` } func GetInfo(api string) ([]Person, error) { url := fmt.Sprintf("%s/person?addr=%s", api, ADDRESS) resp, err := http.Get(url) if err != nil { return []Person{}, err } if resp.StatusCode != http.StatusOK { return []Person{}, fmt.Errorf("get info didn’t respond 200 OK: %s", resp.Status) } return nil, nil } </code></pre>

当然运行go test也会返回一个错误,因为请求地址的问题,请求的并不是一个实际上的http server,那么自然也不会有正常的返回。
 

 

<span style="color:#ff6666;">三、Golang httptest</span>

上面一个例子很有用,但是如何去发送一个真正的http request而不去真正的启动一个http server(亦或者请求任意的server)?答案是使用Go 的httptest包,这个包可以非常简单的创建一个测试的http server,那么下面我们将展示一下完整的代码,并解释一下整体的测试流程:

person.go:

 

<pre class="has"><code class="language-cpp">package person import ( "net/http" "fmt" "io/ioutil" "encoding/json" "github.com/astaxie/beego/logs" ) const ( ADDRESS = "shanghai" ) type Person struct { Name string `json:"name"` Address string `json:"address"` Age int `json:"age"` } func GetInfo(api string) ([]Person, error) { url := fmt.Sprintf("%s/person?addr=%s", api, ADDRESS) resp, err := http.Get(url) defer resp.Body.Close() if err != nil { return []Person{}, err } if resp.StatusCode != http.StatusOK { return []Person{}, fmt.Errorf("get info didn’t respond 200 OK: %s", resp.Status) } bodyBytes, _ := ioutil.ReadAll(resp.Body) personList := make([]Person,0) err = json.Unmarshal(bodyBytes, &personList) if err != nil { logs.Error("decode data fail") return []Person{}, fmt.Errorf("decode data fail") } return personList, nil }</code></pre>

person_test.go:

 

<pre class="has"><code class="language-cpp">package person import ( "testing" "net/http/httptest" "net/http" "fmt" "encoding/json" ) var personResponse = []Person{ { Name : "wahaha", Address : "shanghai", Age : 20, }, { Name : "lebaishi", Address : "shanghai", Age : 10, }, } var personResponseBytes, _ = json.Marshal(personResponse) func TestPublishWrongResponseStatus(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write(personResponseBytes) if r.Method != "GET"{ t.Errorf("Expected 'GET' request, got '%s'", r.Method) } if r.URL.EscapedPath() != "/person" { t.Errorf("Expected request to '/person', got '%s'", r.URL.EscapedPath()) } r.ParseForm() topic := r.Form.Get("addr") if topic != "shanghai" { t.Errorf("Expected request to have 'addr=shanghai', got: '%s'", topic) } })) defer ts.Close() api := ts.URL fmt.Println("url:", api) resp, _ := GetInfo(api) fmt.Println("reps:", resp) } </code></pre>

解释一下:

 

>我们通过httptest.NewServer创建了一个测试的http server

>读请求设置通过变量r *http.Request,写变量(也就是返回值)通过w http.ResponseWriter

>通过ts.URL来获取请求的URL(一般都是<http://ip:port>)

>通过r.Method来获取请求的方法,来测试判断我们的请求方法是否正确

>获取请求路径:r.URL.EscapedPath(),本例中的请求路径就是"/person"

>获取请求参数:r.ParseForm,r.Form.Get("addr")

>设置返回的状态码:w.WriteHeader(http.StatusOK)

>设置返回的内容(这就是我们想要的结果):w.Write(personResponseBytes),注意w.Write()接收的参数是[]byte,因此需要将object对象列表通过json.Marshal(personResponse)转换成字节。

 

综上,我们可以通过不发送httptest来模拟出httpserver和返回值来进行自己代码的测试了。

 

 

Author:忆之独秀

Email:leaguenew@qq.com

注明出处:http://blog.csdn.net/lavorange/article/details/73369153

 

 

到此这篇关于“Golang单元测试之httptest使用”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Golang单元测试之httptest使用
Golang单元测试:有哪些误区和实践?
学习单元测试,告别祈祷式编程
:first-child和:last-child学习笔记
golang基础教程
Go单元测试:为什么stub叫做桩函数,mock叫做模拟接口?
golang 示例测试example_Golang基础入门11 | Testing
php有必要做单元测试吗
go mockweb接口_golang 单元测试(gotests、mockery自动生成)
Go语言测试——TDD

[关闭]
~ ~