GoMock入門:初心者向けの使い方とテストの書き方
はじめに
GoMockは、Go言語でモック(Mock)を使ったテストを簡単に書けるようにするライブラリです。
外部APIやデータベースに依存するコードをテストする際、GoMockを使うことで依存関係を分離し、効率的なユニットテストが実現できます。
本記事では、GoMockの基本的な使い方を中心に、以下の内容を解説します。
対象読者
- Go言語のテストを学び始めた方
- 外部APIやDBに依存しないテストを書きたい方
- GoMockを使ってモックを作成したい方
目次
- GoMockとは?
- インストール方法
- 基本的な使い方
- モックの生成
- モックの設定
- モックの検証
- 実践:GoMockを使ったユニットテスト
1. そもそもGoMockとは?
GoMockは、Go言語用のモック生成ライブラリで、以下の特徴があります。
- 依存関係を分離して、テスト対象の関数やメソッドだけを検証できる。
- gomock.Controllerを使って、モックの動作を設定・検証できる。
- Mockgenというツールを使って、インターフェースからモックコードを自動生成 できる。
2. インストール方法
1. GoMockとMockgenのインストール
以下のコマンドを実行して、GoMockとMockgenをインストールします。
go install github.com/golang/mock/mockgen@latest
.zshrc
または.bash_profile
に以下を追加して、環境変数PATH
を設定します。
export PATH=$PATH:$(go env GOPATH)/bin
設定を反映させるために、以下を実行します。
source ~/.zshrc # Zshを使用している場合
source ~/.bash_profile # Bashを使用している場合
2. Go Modulesに追加
go.mod
にGoMockを追加します。
go get github.com/golang/mock/gomock
3. 基本的な使い方
3.1 モックの生成
Mockgenを使って、インターフェースからモックを自動生成します。
今回は、UserRepository
インターフェースをモック化してみます。
user.go
package example
type User struct {
ID int
Name string
}
type UserRepository interface {
GetUser(id int) (*User, error)
}
以下のコマンドを実行して、モックを生成します。
mockgen -source=user.go -destination=mock_user.go -package=example
-
-source
: モックを生成する元のインターフェースを含むファイル -
-destination
: 生成されるモックのファイル名 -
-package
: モックを含むパッケージ名
3.2 モックの設定
gomock.Controller
を使って、モックの動作を設定します。
user_test.go
package example_test
import (
"errors"
"testing"
"github.com/golang/mock/gomock"
"example"
)
func TestGetUser_Success(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockRepo := example.NewMockUserRepository(ctrl)
mockRepo.EXPECT().GetUser(1).Return(&example.User{ID: 1, Name: "John"}, nil)
user, err := mockRepo.GetUser(1)
if err != nil {
t.Fatal("expected no error, but got", err)
}
if user.Name != "John" {
t.Fatal("expected user name to be John, but got", user.Name)
}
}
3.3 モックの検証
-
EXPECT()
を使って、モックの動作を設定 -
Return()
を使って、モックの返り値を設定 -
ctrl.Finish()
で、呼び出し回数の検証 を行う
4. 実践:GoMockを使ったユニットテスト
GoMockを使って、外部依存を分離したユニットテストを実装します。
今回は、UserService
がUserRepository
に依存しているケースをテストします。
4.1 UserServiceの実装
user_service.go
package example
import "errors"
type UserService struct {
repo UserRepository
}
func NewUserService(repo UserRepository) *UserService {
return &UserService{repo: repo}
}
func (s *UserService) GetUserName(id int) (string, error) {
user, err := s.repo.GetUser(id)
if err != nil {
return "", err
}
if user == nil {
return "", errors.New("user not found")
}
return user.Name, nil
}
4.2 UserServiceのテスト実装
user_service_test.go
package example_test
import (
"errors"
"testing"
"github.com/golang/mock/gomock"
"example"
)
func TestGetUserName_Success(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockRepo := example.NewMockUserRepository(ctrl)
mockRepo.EXPECT().GetUser(1).Return(&example.User{ID: 1, Name: "John"}, nil)
service := example.NewUserService(mockRepo)
name, err := service.GetUserName(1)
if err != nil {
t.Fatal("expected no error, but got", err)
}
if name != "John" {
t.Fatal("expected name to be John, but got", name)
}
}
func TestGetUserName_NotFound(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockRepo := example.NewMockUserRepository(ctrl)
mockRepo.EXPECT().GetUser(1).Return(nil, nil)
service := example.NewUserService(mockRepo)
_, err := service.GetUserName(1)
if err == nil || err.Error() != "user not found" {
t.Fatal("expected user not found error, but got", err)
}
}
-
mockRepo.EXPECT()
を使って、期待する動作を設定 - テストケースとして、成功ケースとユーザーが見つからないケースを実装
まとめ
項目 | 説明 |
---|---|
GoMock | Go言語用のモック生成ライブラリ |
Mockgen | インターフェースからモックを自動生成 |
Controller | モックの動作を設定・検証する |
GoMockを使うことで、外部依存を切り離してテストできるため、高品質なユニットテストを効率的に書くことが可能になります!
Discussion