0
0

More than 1 year has passed since last update.

【GoでMockを差し込めるようにリファクタリングした】

Posted at

現在Goで作っているアプリケーションを先輩からアドバイスをもらって、より疎結合に実装できるようになったのでまとめる。(MVCの概念の中で行うことを前提にしています)

何をMock化したいのか?

今回のリファクタリングを通じて思ったのは、「どこの関数をmock化したいのか」をまず考えるべきと言うこと。

今回の例だとcontrollerのuser.setvalue()をmock化できればCreateUserの単体テストが楽になりそうだ。

userController.go

package controllers

import (    
    "app/~/models"
    "github.com/gin-gonic/gin"
)

func CreateUser(c *gin.Context) {
    user := &models.User{}
    c.BindJSON(user)

    user.SetValue(*user) /* <--------- ここをMock化できたらよさそう*/

    c.JSON(200, gin.H{
        "result": true,
    })
}

どうやってやるのか?

Model側の設定

このuser.setvalue()はUserModelの関数であるため、UserModelが実装となるinterfaceを定義してあげる必要がある。

userModel.goとuserInterface.go

package models

type User struct {
    Name                 string  `json:"name"`
    Email                string  `json:"email"`
}

func (u *User) SetValue(user User) {
    // 具体的な処理
}
package models

type UserInterface interface {
    SetValue(user User)
}

これで、userModelの代わりとなるをmockを差し込むためのModel側の準備は完了。

controller側の修正

あとは、mockを使うのか実際のmodelを使うのかをインスタンスを生成するタイミングで差し込んであげればいい(コンストラクタインジェクションともいう。)のでそのための修正をcontrollerに加える。

オブジェクト指向言語であれば、コンストラクタがあるのでそこの引数とインスタンス変数で実現できる。しかし、Goにはこういったものはないので独自にNew関数とインスタンス変数っぽいものを作る。New+〜とするのが推奨されているらしい。

修正後 userController.go

package controllers

import (    
    "app/~/models"
    "github.com/gin-gonic/gin"
)

type UserRepository struct {
    User models.UserInterface /* <-- インスタンス変数っぽく扱うもの */
}

/* コンストラクタの代わりになるもの */
func NewUserRepository(user models.UserInterface) *UserRepository {
    return &UserRepository{
        user,
    }
}

func (r *UserRepository) CreateUser(c *gin.Context) {
    user := &models.User{}
    c.BindJSON(user)

    r.user.SetValue(*user) /* <--------- UserRepositoryのUserのSetValueを使用する*/

    c.JSON(200, gin.H{
        "result": true,
    })
}

実際にNewするところ

これでようやくインスタンス生成時に、インターフェースを介して疎結合にモデルかmockを差し込める。
controllerに処理を渡す上位層でNewすればいい。
&models.User{}をMockにすれば、CreateUser()の単体テストは楽になるだろう¥

userCnt := controllers.NewUserRepository(&models.User{})
userCnt.CreateUser()

まとめ

Goで疎結合な設計を行うためには、構造体とinterfaceをうまく使う必要がある。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0