GodeAPIを作り始めたのはいいのですが、コントローラーのテストを行なった際に循環参照が発生してハマりました。フレームワークはginを使用しています
循環参照が発生するソース
/controller/user_controller_test.go
package controller
import (
>..."github.com/ashiato/config"
>..."github.com/ashiato/db"
>..."github.com/stretchr/testify/assert"
>..."net/http"
>..."net/http/httptest"
>..."testing"
)
//func TestLoginSuccess(t *testing.T) {
func TestIndexSuccess(t *testing.T) {
>...//DB接続
>...db.Init()
>...//ルーティング設定
>...router := config.Router{}
>...ro := router.LoadRoute()
>...w := httptest.NewRecorder()
>...req, _ := http.NewRequest("GET", "/user", nil)
>...ro.ServeHTTP(w, req)
>...assert.Equal(t, 200, w.Code)
}
/config/router.go
package config
import (
>..."github.com/ashiato/controller"
>..."github.com/gin-gonic/gin"
)
type Router struct{}
// Init is initialize server
func (ro Router) Init() {
>...r := ro.LoadRoute()
>...r.Run()
}
func (ro Router) LoadRoute() *gin.Engine {
>...r := gin.Default()
>...u := r.Group("/user")
>...{
>...>...ctrl := controller.UserController{}
>...>...u.GET("", ctrl.Index)
>...}
>...return r
}
テストはhttps://gin-gonic.com/ja/docs/testing/ に習ってrouter.goのLoadRouteを呼び出しています。そのためgithub.com/ashiato/configパッケージを読み込んでいるのですが、
router.goはコントローラーのメソッドを呼び出しているためgithub.com/ashiato/controllerが必要です、この時循環参照が発生します。
configに入っているrouterをcontrollerに持っていくとソースの見通しが悪くなり、逆もまた然り、
かと行ってテストでルーターを作成するのは2重管理になってしまい嫌です。
そんな時こちらの記事をでこんな記載がありました
抜粋
Goは同じディレクトリ以下に複数のpackage名を許さないが、例外的にxxxパッケージとxxx_testパッケージは同じディレクトリに共存できる。
当然異なるパッケージになるので、非公開メソッドなどは参照できなくなるが、循環参照を回避できる。
また、非公開な機能をexport_test.goを介してアクセスすることもできる。
なるほど、そういうことでしたか!
ということで修正します
/controller/user_controller_test.go
package controller_test // 変更
import (
>..."github.com/ashiato/config"
>..."github.com/ashiato/db"
>..."github.com/stretchr/testify/assert"
>..."net/http"
>..."net/http/httptest"
>..."testing"
)
//func TestLoginSuccess(t *testing.T) {
func TestIndexSuccess(t *testing.T) {
>...//DB接続
>...db.Init()
>...//ルーティング設定
>...router := config.Router{}
>...ro := router.LoadRoute()
>...w := httptest.NewRecorder()
>...req, _ := http.NewRequest("GET", "/user", nil)
>...ro.ServeHTTP(w, req)
>...assert.Equal(t, 200, w.Code)
}
これでうまくいきました、まだまだGolangと仲良くなれません。