LoginSignup
46
27

More than 3 years have passed since last update.

go-sqlmockを使ってGORMで書いたコードをテストする

Posted at

gopher.png

gormを使ったコードのテストをするとき、Dockerなどを使ってDBを立ち上げてテストする必要がありますが、go-sqlmockを使うと、実際のDBの代わりにモックを使ってテストすることができます。

この記事は、簡単なモデルを例にしたサンプルコードです。

パッケージのインストール

gormとgo-sqlmockは以下のコマンドでインストールできます。

go get -u github.com/jinzhu/gorm
go get -u github.com/DATA-DOG/go-sqlmock

テスト対象のソース

RepositoryパターンでCreateとGetをGormで実装した例です。

user/user.go
package user

import (
    "github.com/jinzhu/gorm"
)

type User struct {
    ID   string `gorm:"primary_key"`
    Name string
}

type Repository struct {
    *gorm.DB
}

func (p *Repository) Create(id string, name string) error {
    person := &User{
        ID:   id,
        Name: name,
    }
    return p.DB.Create(person).Error
}

func (p *Repository) Get(id string) (*User, error) {
    var person User

    err := p.DB.Where("id = ?", id).Find(&person).Error
    return &person, err
}

テストコード

先程のコードの、CreateとGetをそれぞれテストしてみます。

まず、DBモックとGORMのオープンです。

user/user_test.go
package user

import (
    "regexp"
    "testing"

    sqlmock "github.com/DATA-DOG/go-sqlmock"
    "github.com/jinzhu/gorm"
)

func getDBMock() (*gorm.DB, sqlmock.Sqlmock, error) {
    db, mock, err := sqlmock.New()
    if err != nil {
        return nil, nil, err
    }

    gdb, err := gorm.Open("postgres", db)
    if err != nil {
        return nil, nil, err
    }
    return gdb, mock, nil
}

これを使ってテストを書いてみます。

Createのテスト

user/user_test.go
func TestCreate(t *testing.T) {
    db, mock, err := getDBMock()
    if err != nil {
        t.Fatal(err)
    }
    defer db.Close()
    db.LogMode(true)

    r := Repository{DB: db}

    id := "2222"
    name := "BBBB"

    // Mock設定
    mock.ExpectQuery(regexp.QuoteMeta(
        `INSERT INTO "users" ("id","name") VALUES ($1,$2)
         RETURNING "users"."id"`)).
        WithArgs(id, name).
        WillReturnRows(
            sqlmock.NewRows([]string{"id"}).AddRow(id))

    // 実行
    err = r.Create(id, name)
    if err != nil {
        t.Fatal(err)
    }
}

mock.ExpectQueryのところで、期待するSQLとパラメータと、実行結果のレコードを設定しています。
実際に実行した時に、この期待結果と異なる場合、以下のようなエラーが返ります。

--- FAIL: TestCreate (0.00s)
    user_test.go:48: Query 'INSERT INTO "users" ("id","name") VALUES ($1,$2) RETURNING "users"."id"', arguments do not match: argument 0 expected [string - 2222X] does not match actual [string - 2222]

Getのテスト

user/user_test.go
func TestGet(t *testing.T) {
    db, mock, err := getDBMock()
    if err != nil {
        t.Fatal(err)
    }
    defer db.Close()
    db.LogMode(true)

    r := Repository{DB: db}

    id := "1111"
    name := "AAAA"

    // Mock設定
    mock.ExpectQuery(regexp.QuoteMeta(
        `SELECT * FROM "users" WHERE (id = $1)`)).
        WithArgs(id).
        WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).
            AddRow(id, name))

    // 実行
    res, err := r.Get(id)
    if err != nil {
        t.Fatal(err)
    }

    if res.ID != id || res.Name != name {
        t.Errorf("取得結果不一致  %+v", res)
    }
}
46
27
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
46
27