golang Layered Testing tutorial for http Interface testing
- 2020-06-23 00:36:12
- OfStack
preface
The first few sentences are mainly about using golang for unit testing. The first layer of unit testing is interface testing. This section is mainly about using golang for interface testing, which is mainly about using http protocol interface testing
http request in golang
There is a native http dependency library in golang: net/http, which will be used by the establishment of http server or the development of http client. Here, the client part is mainly explained as the initiator of the request and applied to daily interface test. The example code is as follows:
get request
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
// simulation 1 a get Submit a request
resp, err := http.Get("http://127.0.0.1:12345/checkon")
if err != nil {
panic(err)
}
defer resp.Body.Close() // Close the connection
body, err := ioutil.ReadAll(resp.Body) // read body The content of the
fmt.Println(string(body))
}
Returns the result
E:\go_project>go run testget.go
{
"code": 200,
"data": "",
"msg": "online",
"state": "success"
}
post request:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
)
func main() {
// simulation 1 a post Submit a request
resp, err := http.Post("http://www.baidu.com", "application/x-www-form-urlencoded", strings.NewReader("id=1"))
if err != nil {
panic(err)
}
// Close the connection
defer resp.Body.Close()
// Read all contents of the message
body, err := ioutil.ReadAll(resp.Body)
// output
fmt.Println(string(body))
}
The post request above is in form fashion and returns 1 page
Here's the following line of code
defer resp.Body.Close()
The first is defer. The defer statement of Go is used to schedule a function call (deferred) to be run before the return of the function that executed defer. The deferred function whose arguments (including the receiver) are evaluated at defer execution, rather than at call execution. That is to be extended to perform the function of the parameter is in normal order is evaluated, the simple understanding for, whether defer corresponding lines of code in the code segment which position, defer is performed before return lines of code, but defer the parameters in the line of code is need statement first, then call, corresponding to the response of the processing, golang Response. Body need to be closed, body had, in fact, a nested layers of net. TCPConn:
Can be seen from the above if body was neither read completely, has not been closed, so the http transaction is not completed, unless the connection because of a timeout, the related resources can't be recycled, so we need to close the connection operation, this is many novice golang ignore 1 point, as dealing with response client end, body1 must close, otherwise it will cause GC recycling, which in turn generate memory leaks
post request with json
Most of the restful interfaces we use are request bodies in json format, and the corresponding http request bodies in post format also have related ways
package main
import (
"fmt"
"io/ioutil"
"net/http"
"bytes"
"encoding/json"
)
type HttpData struct {
Flag int `json:"flag"`
Msg string `json:"msg"`
}
func main() {
url := "http://127.0.0.1:12345/postdata"
contentType := "application/json;charset=utf-8"
var httpdata HttpData
httpdata.Flag = 1
httpdata.Msg = "terrychow"
b ,err := json.Marshal(httpdata)
if err != nil {
fmt.Println("json format error:", err)
return
}
body := bytes.NewBuffer(b)
resp, err := http.Post(url, contentType, body)
if err != nil {
fmt.Println("Post failed:", err)
return
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Read failed:", err)
return
}
fmt.Println("header:", resp.Header)
fmt.Println("content:", string(content))
}
Execute result response
E:\go_project>go run gohttptest.go
header: map[Content-Type:[application/json] Content-Length:[78] Server:[Werkzeug/0.14.1 Python/2.7.15] Date:[Thu, 06 Dec 2018 16:35:11 GMT]]
content: {
"code": 200,
"data": 1,
"msg": "terrychow",
"state": "success"
}
The common get and post requests are basically executed as above. Of course, what we need to do now is to test the http interface, so we need to introduce the test framework for verification. This article first explains how to use the gocheck mentioned before to make assertions
http interface tests in golang
After introducing gocheck, we got the following script:
package hello_test
import (
"testing"
"fmt"
"strconv"
"io/ioutil"
"net/http"
"bytes"
"encoding/json"
. "gopkg.in/check.v1"
)
var a int =1
// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { TestingT(t) }
type MySuite struct{}
type HttpData struct {
Flag int `json:"flag"`
Msg string `json:"msg"`
}
var _ = Suite(&MySuite{})
var testurl string ="http://127.0.0.1:12345"
func (s *MySuite) SetUpSuite(c *C) {
str3:=" The first 1 The second suite starts execution "
fmt.Println(str3)
//c.Skip("Skip TestSutie")
}
func (s *MySuite) TearDownSuite(c *C) {
str4:=" The first 1 The sub-suite execution is complete "
fmt.Println(str4)
}
func (s *MySuite) SetUpTest(c *C) {
str1:=" The first "+strconv.Itoa(a)+" The use case begins execution "
fmt.Println(str1)
}
func (s *MySuite) TearDownTest(c *C) {
str2:=" The first "+strconv.Itoa(a)+" Bar use case execution completes "
fmt.Println(str2)
a=a+1
}
func (s *MySuite) TestHttpGet(c *C) {
geturl := fmt.Sprintf("%v/checkon", testurl)
respget, err := http.Get(geturl)
if err != nil {
panic(err)
}
defer respget.Body.Close() // Close the connection
body, err := ioutil.ReadAll(respget.Body) // read body The content of the
var gdat map[string]interface{} // define map Used to resolve resp.body The content of the
if err := json.Unmarshal([]byte(string(body)), &gdat); err == nil {
fmt.Println(gdat)
} else {
fmt.Println(err)
}
var gmsg=gdat["msg"]
c.Assert(gmsg, Equals, "terrychow") // Simulate failed assertions
}
func (s *MySuite) TestHttpPost(c *C) {
url := fmt.Sprintf("%v/postdata", testurl)
contentType := "application/json;charset=utf-8"
var httpdata HttpData
httpdata.Flag = 1
httpdata.Msg = "terrychow"
b ,err := json.Marshal(httpdata)
if err != nil {
fmt.Println("json format error:", err)
return
}
body := bytes.NewBuffer(b)
resp, err := http.Post(url, contentType, body)
if err != nil {
fmt.Println("Post failed:", err)
return
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Read failed:", err)
return
}
var dat map[string]interface{} // define map Used to resolve resp.body The content of the
if err := json.Unmarshal([]byte(string(content)), &dat); err == nil {
fmt.Println(dat)
} else {
fmt.Println(err)
}
var msg=dat["msg"]
c.Assert(msg, Equals, "terrychow") // Simulate successful assertions
}
The final output content:
E:\go_project>go test -v gocheckhttp_test.go
=== RUN Test
The first 1 The second suite starts execution
The first 1 The use case begins execution
map[code:200 data: msg:online state:success]
The first 1 Bar use case execution completes
----------------------------------------------------------------------
FAIL: gocheckhttp_test.go:56: MySuite.TestHttpGet
gocheckhttp_test.go:72:
c.Assert(gmsg, Equals, "terrychow")
... obtained string = "online"
... expected string = "terrychow"
The first 2 The use case begins execution
map[msg:terrychow state:success code:200 data:1]
The first 2 Bar use case execution completes
The first 1 The sub-suite execution is complete
OOPS: 1 passed, 1 FAILED
--- FAIL: Test (0.02s)
FAIL
FAIL command-line-arguments 0.613s
The output is as expected, and this is the basic http interface test
summary