Fusic Tech Blog

Fusicエンジニアによる技術ブログ

DATA-DOG/go-sqlmockを使ってGormDBをmockする
2024/02/19

DATA-DOG/go-sqlmockを使ってGormDBをmockする

本記事はGo Advent Calendar 2020の2日目の記事 およびFusic Advent Calendar 2020の2日目の記事です。

以前GoでRDBのテストを書く時

  • テスト用のDBを用意しておく
  • テスト実行時CreateTableをする
  • データを挿入する
  • テストを実行する
  • テスト終了時DropTableをする

ということをしてました。

DBの振る舞いをテストするだけならここまでする必要はないなと思っており、実行速度も気になっていました。

そこで今回は普段使っているORMであるGormに対してgo-sqlmockを用いて
GormDBをmockする方法をご紹介します。

mockを作成

sql-mockはsqlmock.New()という関数を持っており、
そちらを利用するとテスト関数に渡すDBと振る舞いを定義出来るmockを返してくれます。
さらに今回Gormを使用したいので、そのDBに対してgorm用のコネクションを作成しておきます。
僕はPostgreSQLを利用していたので、PostgreSQL用のコネクションを生成します。

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

    gormDB, err := gorm.Open(
        postgres.New(
            postgres.Config{
                Conn: db,
            }), &gorm.Config{})

    if err != nil {
        return gormDB, mock, err
    }

    return gormDB, mock, err
}

各テスト用のメソッドではこのGormDBとmockを利用して振る舞いをテストしていきます。

SELECT系

SELECT系のテストを行うときは mock.ExpectQueryを利用します。
その振る舞いをチェックするにあたり、一致するようなSQLを記述する必要があるのですが、
わりと面倒なので、僕の場合はいい加減なSQLをまず実行します。

ここでは hogeというQueryを投げてしまいます。

あとは実際に実行したいDBに対して、テスト対象の関数を通してみます。
今回はTagテーブルに対してSELECTを行うGetTagのテストを行います。

func TestGetTag(t *testing.T) {
    db, mock, err := GetNewDbMock()
    if err != nil {
        t.Errorf("Failed to initialize mock DB: %v", err)
        return
    }

    mock.ExpectQuery(regexp.QuoteMeta(`hoge`))

    res, err := GetTag(db, 1)

    assert.Equal(t, err, nil)
    assert.NotEqual(t, res, nil)
}
$ go test ./...

****/models/tag_func.go:12 Query: could not match actual sql: "SELECT * FROM "tags" WHERE id = $1" with expected regexp "hoge"
[0.041ms] [rows:0] SELECT * FROM "tags" WHERE id = 1
shiro seike / せいけ しろう / 清家 史郎

shiro seike / せいけ しろう / 清家 史郎

Company:Fusic CO., LTD. Slides:slide.seike460.com blog:blog.seike460.com Program Language:PHP , Go Interest:Full Serverless Architecture