我們可以把它想成Unit Test單元測試的一種,不過它所涵蓋的最好集合不像以往的UnitTest可能以Function
為主,而是Endpoint
。
透過API Test我們能夠在開發與修改程式碼時,確保被修改到部分程式碼的API能夠如預期的運作,那這邊我們會以官方提供的httptest
來實作。
首先我們將main當中的router部分給分離出來
main.go
package main
import (
"fmt"
"github.com/chenyahui/gin-cache/persist"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8"
"github.com/joho/godotenv"
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
"ironman-2021/app/config"
"ironman-2021/app/dao"
"ironman-2021/app/middleware"
"ironman-2021/app/model"
"net/http"
"os"
)
// @title Gin swagger
// @version 1.0
// @description Gin swagger
// @contact.name Flynn Sun
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
// schemes http
// @securityDefinitions.apikey BearerAuth
// @in header
// @name Authorization
func main() {
envErr := godotenv.Load()
if envErr != nil {
panic(envErr)
}
port := os.Getenv("PORT")
server := SetRouter()
err := server.Run(":" + port)
if err != nil {
panic(err)
}
}
func SetRouter() *gin.Engine {
envErr := godotenv.Load()
if envErr != nil {
panic(envErr)
}
dbConfig := os.Getenv("DB_CONFIG")
db, ormErr := dao.Initialize(dbConfig)
if ormErr != nil {
panic(ormErr)
}
migrateErr := db.AutoMigrate(&model.User{})
if migrateErr != nil {
return nil
}
server := gin.Default()
server.Use(middleware.CORSMiddleware())
server.GET("/hc", func(c *gin.Context) {
c.String(http.StatusOK, fmt.Sprintf("Health Check"))
})
redisStore := persist.NewRedisStore(redis.NewClient(&redis.Options{
Network: "tcp",
Addr: "redis:6379",
DB: 0,
}))
config.RouteUsers(server, redisStore)
url := ginSwagger.URL("http://localhost:8080/swagger/doc.json")
server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url))
return server
}
接著則在專案的根目錄加上一個main_test.go
的檔案
main_test.go
package main
import (
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"testing"
)
func Test_setupRouter(t *testing.T) {
router := SetRouter()
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/hc", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "Health Check")
}
ResponseRecorder
的物件/hc
的Response給conform到ResponseRecorder
docker exec -it ironman-2021 bash 4280 16:27:57
root@88c2c60ca49b:/usr/local/go/src/ironman-2021# ls
go test -v
的command執行單元測試go test -v
=== RUN Test_setupRouter
[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 /hc --> ironman-2021.SetRouter.func1 (4 handlers)
[GIN-debug] POST /v1/users/ --> ironman-2021/app/controller.UsersController.CreateUser-fm (4 handlers)
[GIN-debug] GET /v1/users/:id --> ironman-2021/app/controller.UsersController.GetUser-fm (6 handlers)
[GIN-debug] POST /v1/users/login --> ironman-2021/app/controller.UsersController.AuthHandler-fm (4 handlers)
[GIN-debug] GET /swagger/*any --> github.com/swaggo/gin-swagger.CustomWrapHandler.func1 (4 handlers)
[GIN] 2021/10/08 - 08:29:40 | 200 | 107.8µs | | GET "/hc"
--- PASS: Test_setupRouter (0.06s)
PASS
ok ironman-2021 0.100s
那從這我們就可以看到他執行單元測試的結果與耗費時間等資料,用以確認是否程式碼如預期地運作!
再來我們就可以依序寫更多的Test Code,從Create a new user 到 Login with an existing user等
package main
import (
"bytes"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"testing"
)
func Test_setupRouter(t *testing.T) {
router := SetRouter()
w := httptest.NewRecorder()
req1, _ := http.NewRequest("GET", "/hc", nil)
router.ServeHTTP(w, req1)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "Health Check")
var jsonStr1 = []byte(`{"account":"account","password":"password", "email":"test123@gmail.com"}`)
req2, _ := http.NewRequest("POST", "/v1/users/", bytes.NewBuffer(jsonStr1))
router.ServeHTTP(w, req2)
assert.Equal(t, http.StatusOK, w.Code)
var jsonStr2 = []byte(`{"account":"account","password":"password"`)
req3, _:= http.NewRequest("POST", "/v1/users/login/", bytes.NewBuffer(jsonStr2))
router.ServeHTTP(w, req3)
assert.Equal(t, http.StatusOK, w.Code)
}
這章節主要介紹如何使用官方的httptest
來寫Http Test,希望能降低修改程式碼時出錯的概率!
相關的程式碼一樣會放在下方連結。
https://github.com/Neskem/Ironman-2021/tree/Day-25