😎
DBアクセスをモック化した自動テスト(Go+echo)
バージョン
go version go1.20.1 darwin/amd64
echo v3.3.10-dev
以下の記事を参考にさせていただきました
ユーザーを一意に特定できる情報でDBを参照して、ユーザーが特定できた場合のテストと、ユーザーが特定できなかった場合のエラーとするテストコードです。
route.go
func Requestroute() {
router := NewRouter()
router.Logger.Fatal(router.Start(":" + config.Port))
}
func NewRouter() *echo.Echo {
e := echo.New()
e.GET("/get", func(ctx echo.Context) error {
handler := IniHandler(models.NewUserModel())
return handler.GetReq(ctx)
})
return e
}
usersHandler.go
package controllers
import (
"fmt"
"itodo/app/models"
"net/http"
"github.com/labstack/echo"
)
type (
userhandler struct {
user models.UserModel
}
)
func IniHandler(u models.UserModel) *userhandler {
return &userhandler{u}
}
func (h userhandler) GetReq(c echo.Context) error {
var userid int = 1
h.user.Fetch(userid)
var uuid string = h.user.GetName()
if uuid == "" {
return echo.NewHTTPError(http.StatusNotFound)
}
return c.String(http.StatusOK, uuid)
}
モデル
users.go
type (
UserModel interface {
Fetch(id int)
GetName() string
}
userModel struct {
uuid string
}
)
func NewUserModel() *userModel {
return &userModel{}
}
func (u *userModel) GetName() string {
return u.uuid
}
func (u *userModel) Fetch(id int) {
if id < 1 {
return
}
err := Db.QueryRow("SELECT uuid FROM users WHERE id=? LIMIT 1", id).Scan(&u.uuid)
switch {
case err == sql.ErrNoRows:
u.uuid = ""
case err != nil:
panic(err.Error())
}
}
テスト
usersHandler_test.go
package controllers
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/labstack/echo"
"github.com/stretchr/testify/assert"
)
type userModelStub struct {
uuid string
}
func (u *userModelStub) Fetch(id int) {}
func (u *userModelStub) GetName() string { return u.uuid }
func Test_Getreq_Ok(t *testing.T) {
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/req", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
u := &userModelStub{uuid: "test"}
h := IniHandler(u)
h.GetReq(c)
if assert.NoError(t, h.GetReq(c)) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, "test", rec.Body.String())
}
}
func Test_Getreq_404(t *testing.T) {
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/req", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
u := &userModelStub{uuid: ""}
h := IniHandler(u)
err := h.GetReq(c)
if assert.NotNil(t, err) {
err, res := err.(*echo.HTTPError)
if res {
assert.Equal(t, http.StatusNotFound, err.Code)
assert.Equal(t, "Not Found", err.Message)
}
}
}
Go(echo)のテスト標準ではhandlerを使ってDBなどの外部要素をモック化する例が公式のDOCにも記載があります。ソースコードや公式のDOCを少しずつ読み進めて徐々に理解していきたい。
Discussion