単体テスト作成
echoを使ったハンドラのテストを作成します。
作成手順
cf. https://echo.labstack.com/docs/testing
handlerテスト作成
users_handler_test.go
package handler
import (
"bytes"
"easyapp/internal/usecase/params"
"errors"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
type mockUsersUsecase struct {
mock.Mock
}
func (m *mockUsersUsecase) Login(in params.LoginIn) params.LoginOut {
args := m.Called(in)
return args.Get(0).(params.LoginOut)
}
func (m *mockUsersUsecase) Me(in params.MeIn) (params.MeOut, error) {
args := m.Called(in)
return args.Get(0).(params.MeOut), args.Error(1)
}
func Test_UsersHandler_Login(t *testing.T) {
tests := []struct {
name string // テストケース名
requestBody string // リクエストボディ
setupMock func(mock *mockUsersUsecase) // モック設定
expectedStatusCode int // 期待されるHTTPステータス
expectedBody string // 期待されるレスポンスボディ
}{
{
name: "success",
requestBody: `{"name": "nob", "password": "passwd"}`,
setupMock: func(mock *mockUsersUsecase) {
mock.On(
"Login",
params.NewLoginIn(
"nob",
"passwd",
),
).Return(
params.NewLoginOut(true),
)
},
expectedStatusCode: http.StatusOK,
expectedBody: `{"valid": true}`,
},
{
name: "invalid request",
requestBody: `{"name": "nob", "password": "passwd"`, // 末尾の"}"なし
setupMock: func(mock *mockUsersUsecase) {},
expectedStatusCode: http.StatusBadRequest,
expectedBody: `{"message": "Bad request"}`,
},
}
for _, testcase := range tests {
req := httptest.NewRequest(
http.MethodPost,
"/login",
bytes.NewBuffer([]byte(testcase.requestBody)),
)
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
c := echo.New().NewContext(req, rec)
mockUsecase := new(mockUsersUsecase)
testcase.setupMock(mockUsecase)
h := NewUsersHandler(mockUsecase)
if assert.NoError(t, h.Login(c)) {
assert.Equal(t, testcase.expectedStatusCode, rec.Code)
assert.JSONEq(t, testcase.expectedBody, rec.Body.String())
}
}
}
func Test_UsersHandler_Me(t *testing.T) {
tests := []struct {
name string // テストケース名
requestParam map[string]string // リクエストパラメータ
setupMock func(mock *mockUsersUsecase) // モック設定
expectedStatusCode int // 期待されるHTTPステータス
expectedBody string // 期待されるレスポンスボディ
}{
{
name: "success",
requestParam: map[string]string{"name": "nob"},
setupMock: func(mock *mockUsersUsecase) {
mock.On("Me", params.NewMeIn("nob")).Return(params.NewMeOut("nob", 13), nil)
},
expectedStatusCode: http.StatusOK,
expectedBody: `{"name": "nob", "age": 13}`,
},
{
name: "usecase error",
requestParam: map[string]string{"name": "nob"},
setupMock: func(mock *mockUsersUsecase) {
mock.On("Me", params.NewMeIn("nob")).Return(
*new(params.MeOut),
errors.New("不正なユーザ名です。"),
)
},
expectedStatusCode: http.StatusInternalServerError,
expectedBody: `{"message": "Internal server error"}`,
},
}
for _, testcase := range tests {
q := make(url.Values)
q.Set("name", testcase.requestParam["name"])
req := httptest.NewRequest(http.MethodGet, "/me?"+q.Encode(), nil)
rec := httptest.NewRecorder()
c := echo.New().NewContext(req, rec)
mockUsecase := new(mockUsersUsecase)
testcase.setupMock(mockUsecase)
h := NewUsersHandler(mockUsecase)
if assert.NoError(t, h.Me(c)) {
assert.Equal(t, testcase.expectedStatusCode, rec.Code)
assert.JSONEq(t, testcase.expectedBody, rec.Body.String())
}
}
}