1
0

More than 3 years have passed since last update.

golangでDIを行ってみた

Posted at

背景

初めてGo言語を使ってAPIを作っており、テストを書くことに。
以前、Javaを使った開発をしていたので、そのノリでテストを書こうとしたのですが...
書いてみると、mockが上手く使えない...
そこで、Googleさんに色々聞いていたら、どうやらDIというものがあるらしいってなった次第です。

なお、ここに書いてることは自分なりの解釈なので、間違い等ありましたらコメントにてご指摘をお願いします!

DIとは

参考:
猿でも分かる! Dependency Injection: 依存性の注入
やはりあなた方のDependency Injectionはまちがっている。

Dependency Injection=依存性の注入

どうやらDIとは、Dependency Injectionの略のようで、日本語では「依存性の注入」と訳されるらしい。
しかし、依存性の注入とはよく分からない単語だ。

「依存性」と「注入」

以下、自分なりの「依存性」と「注入」の理解になります。

  • 依存性
    依存性とは、あるインスタンス内で他のインスタンスを利用している状態のこと。
  • 注入
    インスタンス内で利用する部品をインスタンス化する段階で渡してあげること。

つまり

う〜ん?要は、インスタンス化するときにそのインスタンス内で使うものを渡してあげれば良い?

Example

今回は簡単に、フレームワークのginを利用してHelloWorldページを実装してみます。

service.go
package action

// ServiceImp is an implimentation of service
type ServiceImp struct {
}

// HelloService return a hello message
func (s ServiceImp) HelloService() string {
    return "Hello World!!"
}

こちらが、サービスのロジックを実装したStructになります。
今回は、Hello World!!と返すだけです。

env.go
package action

import "github.com/gin-gonic/gin"

// ServiceIF is the interface
type ServiceIF interface {
    HelloService() string
}

// Env is service environment
type Env struct {
    Service ServiceIF
}

// NewEnv Constractor for Env
func NewEnv(service ServiceIF) *Env {
    env := Env{Service: service}
    return &env
}

// HelloWorld is the function to display a message
func (e *Env) HelloWorld(c *gin.Context) {
    c.JSON(200, gin.H{"msg": e.Service.HelloService()})
}

そして、他に、ServiceImpを受け取れるインターフェースを持ったEnvを定義します。

main.go
package main

import (
    "sample/action"

    "github.com/gin-gonic/gin"
)

func main() {
    var service action.ServiceImp
    env := action.NewEnv(service)
    r := gin.Default()
    r.GET("/", env.HelloWorld)
    r.Run()
}

上記2つのstructをmain関数の中でインスタンス化します。
このときに、EnvのインスタンスであるenvにはServiceImpのインスタンスであるserviceを渡します。
これで、http://localhost:8080にアクセスすると、無事に”Hello World!!”が表示されました。

利点

こうすることで何が良いかというと。。。
例えば、次のようなServiceImpのモックを作ったとします。

service_mock.go
package action

// ServiceImpMock is an implimentation of service
type ServiceImpMock struct {
}

// HelloService return a hello message
func (s ServiceImpMock) HelloService() string {
    return "This is test..."
}

ここでは、Hello world!!の代わりにThis is test...と返すようにHelloSrviceの中身が変わっています。
そして、以下のようにmain関数でenvに渡すインスタンスをモックに変えます。

main.go(2)
package main

import (
    "sample/action"

    "github.com/gin-gonic/gin"
)

func main() {
    var service action.ServiceImpMock
    env := action.NewEnv(service)
    r := gin.Default()
    r.GET("/", env.HelloWorld)
    r.Run()
}

これで、画面に表示される文字が、”This is test...”へと変わりました。
このように、Envの中で呼び出されるインスタンを外から渡すようにすることで、挙動を変更することができます。
これを使えばテストを書く際などに、モックを作ってあげることで、インスタンス内で呼び出している他の部品の実装に依存しないテストを作成することができるようになります。

まとめ

DIとは、インスタンス内で使用している他のインスタンスをハードコーディングせずに、外部から渡せるようにすること。
これにより、モックを使うことができるようになり、他の部分の実装に依存しないテストが行えるようになります。

1
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
1
0