sqlmock に AnyString で任意の文字を許可させる

## 概要 と 解説

[sqlmock](https://github.com/DATA-DOG/go-sqlmock) はデータベースをモック化して、テストするのに便利なライブラリです。

sqlmock に `AnyString{}` という Struct を定義することで、任意の文字列を Args に与えられるようにします。

たとえば、 user_id を持つ users テーブルへの検索をする際に、次のようなコードで実際のデータベースを用意しなくてもテストすることができます。
次のコードはその疑似コードです。

```golang
db, mock, err := sqlmock.New()
if err != nil {
	t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
}
defer db.Close()

rows := sqlmock.NewRows([]string{"user_id", "created_at", "updated_at"}).AddRow(testdata.UserId, time.Now(), time.Now())
// テストしたいクエリ
query := "SELECT * FROM `users` WHERE user_id = ? LIMIT ?"
mock.ExpectQuery(regexp.QuoteMeta(query)).WithArgs("1").WillReturnRows(rows)

if err = mock.ExpectationsWereMet(); err != nil {
    t.Errorf("Test failed: %v", err)
}
```

今回 `WithArgs("1")` を与えることで、`WHERE user_id = ?` が `WHERE user_id = '1'` として評価されます。
これ自体は問題がないのですが、たとえば user_id がユニークな ID、例として UUIDv4 のような毎回ユニークな値だった場合は `WithArgs("14608bc0-803a-2a74-a349-36cbada1fdda")` のように毎回 Args を指定しないといけません。
しかし、UUIDv4 で user_id を生成している場合、当然ランダムかつユニークな値を Args として指定しなければならず、テストコードに固定の Args を書いておくことはできません。

そこで、ランダムな任意の文字でも Args として与えられるようにします。

## sqlmock での arguments のカスタマイズ

sqlmock では Struct のカスタマイズができるように、Interface が定義されています。
公式の README では `time.Time` を使った arguments の Match をカスタマイズする例が載っています。

```golang
type AnyTime struct{}

// Match satisfies sqlmock.Argument interface
func (a AnyTime) Match(v driver.Value) bool {
	_, ok := v.(time.Time)
	return ok
}

func TestAnyTimeArgument(t *testing.T) {
	t.Parallel()
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	mock.ExpectExec("INSERT INTO users").
		WithArgs("john", AnyTime{}).
		WillReturnResult(sqlmock.NewResult(1, 1))

	_, err = db.Exec("INSERT INTO users(name, created_at) VALUES (?, ?)", "john", time.Now())
	if err != nil {
		t.Errorf("error '%s' was not expected, while inserting a row", err)
	}

	if err := mock.ExpectationsWereMet(); err != nil {
		t.Errorf("there were unfulfilled expectations: %s", err)
	}
}
```

> 上記コードは https://github.com/DATA-DOG/go-sqlmock#matching-arguments-like-timetime
より引用しています

そこで、`_, ok := v.(time.Time)` の部分を `string` に変えた、AnyString struct を定義します。
コードは以下です。

```golang
type AnyString struct{}

// Match satisfies sqlmock.Argument interface
func (a AnyString) Match(v driver.Value) bool {
	_, ok := v.(string)
	return ok
}
```

この AnyString を定義することで、冒頭のテストコードも次のように書き換えられます。

```golang
db, mock, err := sqlmock.New()
if err != nil {
	t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
}
defer db.Close()

rows := sqlmock.NewRows([]string{"user_id", "created_at", "updated_at"}).AddRow(testdata.UserId, time.Now(), time.Now())
// テストしたいクエリ
query := "SELECT * FROM `users` WHERE user_id = ? LIMIT ?"
mock.ExpectQuery(regexp.QuoteMeta(query)).WithArgs(AnyString{}).WillReturnRows(rows)

if err = mock.ExpectationsWereMet(); err != nil {
    t.Errorf("Test failed: %v", err)
}
```

`WithArgs(AnyString{})` で固定の user_id ではなく、`AnyString{}` を渡しています。
これで `WHERE user_id = ?` に UUID のランダムな値が来てもエラーが返らないようになります。

以上です。