kawabatas技術ブログ

試してみたことを書いていきます

【Go言語のtest】interface を利用して mock を使う

概要

外部 API や DB が関わるコードのテストでモックを使いたい場面は多々あると思う。

interface を使って、テストでモックに切り替えることができるのでメモ。

インターフェイスを定義

type DB interface {
    Add(name string) error
    Delete(name string) error
}

実際に使う実装(DynamoDB)

type Dynamo struct {
    DB *dynamodb.DynamoDB
}

// main 関数などからの呼び出し用のコンストラクタ
func NewDynamo() (*Dynamo, error) {
    sess, err := session.NewSession()
    if err != nil {
        return nil, err
    }
    return &Dynamo{DB: dynamodb.New(sess)}, nil
}

func (d *Dynamo) Add(name string) error {
    // 追加の処理。d.DB.PutItem(input)
}
func (d *Dynamo) Delete(name string) error {
    // 削除の処理
}

main から呼び出す

type App struct {
    DB DB
}

func main() {
    db, err := NewDynamo()
    if err != nil {
        log.Fatal(err)
    }

    app := &App{
        DB: db,
    }
    app.DB.Add("hoge")
}

実行すると DynamoDB にデータ追加された

テストの実装

type mockDB struct {
}

func (m *mockDB) Add(name string) error {
    log.Println("=== mock add")
    return nil
}
func (m *mockDB) Delete(name string) error {
    return nil
}

テストから呼び出す

func TestMain(t *testing.T) {
    app := &App{
        DB: &mockDB{},
    }
    app.DB.Add("hoge")
}

テストを実行すると、DynamoDBにデータは追加されいない。

ログも出力され、モックのAddが実行されてる。

その他 Tips

インターフェース埋め込み

type mockDB struct {
  DB
}

func (m *mockDB) Add(name string) error {
    log.Println("=== mock add")
    return nil
}

インターフェースを満たすために DB interface を埋め込むことができる。

func (m *mockDB) Delete(name string) error を用意しなくて済む。