GO言語+ginでテストを書く

##はじめに
とりあえず[sourcegraph.com/github](https://sourcegraph.com/github.com/gin-gonic/gin@8f3047814e86442c8efbd91ef7007905d47cf6c9/-/blob/context_test.go#L517)をみてください。この記事は、先程みてもらったコードの一部を紹介します。
golang+ginで簡単なテストを書いてみます。
テストは難しい
##参考にしたもの
+ ginに書いてあるテストを真似して書きました。
[sourcegraph.com/github](https://sourcegraph.com/github.com/gin-gonic/gin@8f3047814e86442c8efbd91ef7007905d47cf6c9/-/blob/context_test.go#L517)

+ 公式　　
[GoDoc](https://godoc.org/github.com/gin-gonic/gin)

##環境
go version go1.13.8 linux/amd64  

##コード
main.goをつくる。　　
http://localhost:8080/ping
に接続すると"pong"が返ってきます。/ps(post)にして{"name":"someone"}にすると、"someone"メッセージが返ってきます。エラーのときは、"error"が返ってきます。

```go:main.go
package main

import (
	"net/http"

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

type User struct {
	Name string `json:"name" binding:"required"`
}

func router() *gin.Engine {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		// const StatusOK untyped int = 200
		// gin.Hはmap[string]interface{}と同じ
		c.JSON(http.StatusOK, gin.H{"msg": "pong"})
	})
	r.POST("/ps", func(c *gin.Context) {
		var u User
		if err := c.BindJSON(&u); err != nil {
			// const StatusUnauthorized untyped int = 401
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "error"})
			return
		}
		c.JSON(http.StatusOK, gin.H{"msg": u})
	})
	return r
}
func main() {
	router().Run()
}

```

##テストしよう

公式通りのテストです。

```go:テスト１
func TestPingRouter(t *testing.T) {
	router := router()
	w := httptest.NewRecorder()
	//c, _ := gin.CreateTestContext(w)
	req, _ := http.NewRequest("GET", "/ping", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, 200, w.Code)
	// ...
	assert.Equal(t, w.Body.String(), "{\"msg\":\"pong\"}")
}
```
次は、POSTのテストです。
このテストは、"foo"を送ります。そうすると、JSONで返ってきます。そして、"foo"かどうかチェックします。合っていれば、テスト成功です。assert.Equal()をどんどん追加していろいろと試してみると面白そうです。
（補足）
c.Request, _ = http.NewRequest() -> context_test.goの書き方。
req, _ := http.NewRequest() -> ginのチュートリアル的なところの書き方　　
reqとc.Requestは多分同じで、２つとも*Requestでした。

```go:テスト２
func TestPs(t *testing.T) {
	router := router()
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	body := bytes.NewBufferString("{\"name\":\"foo\"}")
	c.Request, _ = http.NewRequest("POST", "/ps", body)
	// req, _ := http.NewRequest("POST", "/ps", body)
	router.ServeHTTP(w, c.Request)

	assert.JSONEq(t, w.Body.String(), "{\"msg\":{\"name\":\"foo\"}}")
	assert.Equal(t, w.Code, 200)
	// ...
}
```
context_test.goにあるものとほとんど同じ

```go:テスト３
func TestPs2(t *testing.T) {
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	body := bytes.NewBufferString("{\"foo\":\"bar\",\"bar\":\"foo\"}")
	c.Request, _ = http.NewRequest("POST", "/ps", body)
	c.Request.Header.Add("Content-Type", binding.MIMEJSON)
	var obj struct {
		Foo string `json:"foo"`
		Bar string `json:"bar"`
	}
	c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "error"})
	assert.Equal(t, w.Code, 401)
	assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")
	assert.NoError(t, c.BindJSON(&obj))
	assert.Equal(t, obj.Foo, "bar")
	assert.Equal(t, obj.Bar, "foo")
	assert.NotEqual(t, obj.Foo, "xxxx")
	assert.Empty(t, c.Errors)
}
```
テスト１は/ping（GET）のテストでテスト２とテスト３は/ps（POST）のテストです。

##おわり

main.goにあるBindJSONについては [ginのBindingとValidationについての調査メモ](https://qiita.com/emonuh/items/3b531fded9b5ede9d93a)