Go言語でテストコードを書く時などに、mockを使いたくなった時があると思います。
この記事を読むことで、どのようにmockを作成するかがわかります。
Go言語でmockを作成する場合、gomockというmockのフレームワークを使用します。
インストールからmock作成までを説明します。
インストール
gomockとmockgenをインストール
go get github.com/golang/mock/gomock
go get github.com/golang/mock/mockgen
実際に試したこと
repositoryとusecaseを作成して、usecaseからrepositoryを呼んで処理をするコードを書く。
テストコード(user_test.go)ではrepositoryの処理はrepository_mockを使用するようにする。
ディレクトリ構成
.
├── repository
│ ├── repository_mock
│ │ └── user_mock.go
│ └── user.go
└── usecase
├── user.go
└── user_test.go
repository/user.go
UserのRepositoryのインターフェースを定義している
「//go:generate mockgen~」はgo generateのコマンドで、mockを作成できるようにソースに追記をしている。
package repository
type User struct {
ID int
Name string
Age int
}
//go:generate mockgen -source=./user.go -destination=./repository_mock/user_mock.go -package=repository_mock
type UserRepository interface {
Get(int) (*User, error)
Create(*User) (*User, error)
}
repository/repository_mock/user_mock.go(作成されたmockのソース)
ルートディレクトリで以下のコマンドを実行してuser_mock.goを作成
go generate ./...
// Code generated by MockGen. DO NOT EDIT.
// Source: ./user.go
// Package repository_mock is a generated GoMock package.
package repository_mock
import (
reflect "reflect"
repository "test/gomock/repository"
gomock "github.com/golang/mock/gomock"
)
// MockUserRepository is a mock of UserRepository interface.
type MockUserRepository struct {
ctrl *gomock.Controller
recorder *MockUserRepositoryMockRecorder
}
// MockUserRepositoryMockRecorder is the mock recorder for MockUserRepository.
type MockUserRepositoryMockRecorder struct {
mock *MockUserRepository
}
// NewMockUserRepository creates a new mock instance.
func NewMockUserRepository(ctrl *gomock.Controller) *MockUserRepository {
mock := &MockUserRepository{ctrl: ctrl}
mock.recorder = &MockUserRepositoryMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockUserRepository) EXPECT() *MockUserRepositoryMockRecorder {
return m.recorder
}
// Create mocks base method.
func (m *MockUserRepository) Create(arg0 *repository.User) (*repository.User, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Create", arg0)
ret0, _ := ret[0].(*repository.User)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Create indicates an expected call of Create.
func (mr *MockUserRepositoryMockRecorder) Create(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockUserRepository)(nil).Create), arg0)
}
// Get mocks base method.
func (m *MockUserRepository) Get(arg0 int) (*repository.User, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", arg0)
ret0, _ := ret[0].(*repository.User)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Get indicates an expected call of Get.
func (mr *MockUserRepositoryMockRecorder) Get(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockUserRepository)(nil).Get), arg0)
}
usecase/user.go
repositoryを使ってUserの作成や取得を行う処理
テストコードではmockを使用する
package usecase
import "test/gomock/repository"
type UserUsecase struct {
repository repository.UserRepository
}
func (u *UserUsecase) List(id int) (*repository.User, error) {
return u.repository.Get(id)
}
func (u *UserUsecase) Create(name string, age int) (*repository.User, error) {
user := &repository.User{
Name: name,
Age: age,
}
return u.repository.Create(user)
}
usecase/user_test.go(テストコード)
mockを使ってテストをすることで、repository/user.goに依存せずに簡単にusecaseのCreateのテストができる。
package usecase
import (
"test/gomock/repository"
"test/gomock/repository/repository_mock"
"testing"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
)
func TestCreate(t *testing.T) {
user := &repository.User{
Name: "taro",
Age: 40,
}
// mockの作成
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mock := repository_mock.NewMockUserRepository(mockCtrl)
mock.EXPECT().Create(user).Return(
&repository.User{
ID: 1,
Name: "taro",
Age: 40,
}, nil,
)
var expect *repository.User = &repository.User{
ID: 1,
Name: "taro",
Age: 40,
}
usecase := &UserUsecase{
repository: mock,
}
// 結果チェック
result, err := usecase.repository.Create(user)
if err != nil {
t.Error("error happen")
}
if diff := cmp.Diff(result, expect); diff != "" {
t.Errorf("User Data miss match :%s", diff)
}
}
まとめ
今回はGo言語で、mockを生成するgomockについて紹介をしてきました。
Go言語について他にselectの仕組みなどの記事を書いておりますので、興味がありましたらそちらも読んでもらたらと思います。
【おすすめ記事のリンク】
コメント