GoでMockを使ったテスト実装
Goで外部と通信するAPI Clientなどを使用しているのテストをMockをつかって書く方法を紹介します。
実装
今回は、下記のように User
という構造体が fetchUserData
という外部からユーザー情報を取得してくるメソッドを持っている例です。
前提として、ユーザー情報を取ってくるAPI Clientは get
というメソッドで外部からデータを取得するものとします。
package sample
type User struct {
Name string
Age int
}
type ApiClient interface {
get(userId int) (name string, age int, err error)
}
func (u *User) fetchUserData(client ApiClient, userId int) error {
var err error
u.Name, u.Age, err = client.get(userId)
if err != nil {
return err
}
return nil
}
fetchUserData
は引数に ApiClient
という interface
を満たすものをとるようになっています。
この場合、ユーザー情報を取ってくるAPI Clientは get
というメソッドを持っている想定なので、 interface
に get
を書いておきます。
これで実際に fetchUserData
を使用する際API Clientを注入すれば期待した通りの動きになりそうですね。
テストコード
さて、上記の実装に対するテストは下記のようになります。
ApiClient
という interface
を満たす ApiClientMock
を作成します。
ApiClientMock
が持つ get
というメソッドは、実際に外部からデータを持ってくる get
メソッドMockとして働きます。
このMockされたgetメソッドは ApiClientMock
のfieldに代入された各情報を返すようになっています。
package sample
import (
"errors"
"testing"
"github.com/google/go-cmp/cmp"
)
type apiClientMock struct {
Name string
Age int
err error
}
func (a apiClientMock) get(userId int) (name string, age int, err error) {
return a.Name, a.Age, a.err
}
func TestUser_fetchUserData(t *testing.T) {
type args struct {
client ApiClient
userId int
}
tests := []struct {
name string
u *User
args argsT
wantUser *User
wantErr bool
}{
{
name: "正しくユーザー情報が取得できること",
u: &User{},
args: args{
client: apiClientMock{
Name: "テスト 太郎",
Age: 25,
err: nil,
},
userId: 1,
},
wantUser: &User{
Name: "テスト 太郎",
Age: 25,
},
wantErr: false,
},
{
name: "取得できなかった場合エラーが返ること",
u: &User{},
args: args{
client: apiClientMock{
err: errors.New("fail get"),
},
userId: 1,
},
wantUser: &User{},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := tt.u.fetchUserData(tt.args.client, tt.args.userId); (err != nil) != tt.wantErr {
t.Errorf("User.fetchUserData() error = %v, wantErr %v", err, tt.wantErr)
}
if diff := cmp.Diff(tt.u, tt.wantUser); diff != "" {
t.Errorf("User value is mismatch (-get + want):\n%s", diff)
}
})
}
}
終わりに
今回は、Goで外部と通信するAPI Clientなどを使用しているのテストをMockをつかって書く方法を紹介しました。
いままでinterfaceをあまり使ったことがなかったのですが、抽象化することで今回やったようなMockを注入できるようになったりできるんだな~と思いました。
自分自身、ほかの言語で外部との通信部をMockに置き換えてテストを書くなどやってきていたのですが、Goでは少してこずったので誰かの参考になれば幸いです。
また、もっとこういったいい方法があるよなど、アドバイスがあればTwitterのDMなどにぜひ送ってくれると喜びます。