テスト可能なGoコードの作成
4499 ワード
テスト分類
開発に関わるテストは主に以下の3種類あり、その他の範囲の広いテスト、例えばシステムテスト、機能テストはここでは紹介しない.
テストの前提条件
これらの概念はJavaのように見えますが、確かに貴重なエンジニアリング実践であり、巨人の肩に立つことを学ばなければなりません.
テストメソッド
mockインタフェース
インタフェースに対してmockを行い、インタフェース関数の入力と出力だけに注目し、詳細を実現する必要はありません.
例:gomock
gomockは、コード内のinterfaceインタフェースに基づいてstubコードを生産する.注入依存後、EXPECTを使用して入力と出力を事前にレイアウトし、呼び出し元の動作が予想と一致するかどうかをテストします.
user.go:
package user
//go:generate mockgen -destination mock_user/mock_user.go github.com/win5do/golang-microservice-demo/docs/sample/gomock/user Index
type Index interface {
Get(key string) interface{}
}
func GetIndex(in Index, key string) interface{} {
// business logic
r := in.Get(key)
// handle output
return r
}
mock_user.go:
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/win5do/golang-microservice-demo/docs/sample/gomock/user (interfaces: Index)
// Package mock_user is a generated GoMock package.
package mock_user
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockIndex is a mock of Index interface
type MockIndex struct {
ctrl *gomock.Controller
recorder *MockIndexMockRecorder
}
// MockIndexMockRecorder is the mock recorder for MockIndex
type MockIndexMockRecorder struct {
mock *MockIndex
}
// NewMockIndex creates a new mock instance
func NewMockIndex(ctrl *gomock.Controller) *MockIndex {
mock := &MockIndex{ctrl: ctrl}
mock.recorder = &MockIndexMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockIndex) EXPECT() *MockIndexMockRecorder {
return m.recorder
}
// Get mocks base method
func (m *MockIndex) Get(arg0 string) interface{} {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", arg0)
ret0, _ := ret[0].(interface{})
return ret0
}
// Get indicates an expected call of Get
func (mr *MockIndexMockRecorder) Get(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockIndex)(nil).Get), arg0)
}
user_test.go:
func TestGetIndex(t *testing.T) {
ctrl := gomock.NewController(t)
index := mock_user.NewMockIndex(ctrl)
in := "uid"
out := "username"
index.EXPECT().Get(in).Return(out)
r := GetIndex(index, "uid")
require.Equal(t, out, r)
}
これは最も簡単な例で、何も見えないかもしれません.考えてみれば、
GetIndex
の論理が非常に複雑であれば、ここでmockはGet
を呼び出す入出力に依存せず、GetIndex
コードを単一測定で100%上書きすることができる.サンプルコード:https://github.com/win5do/go-...
特徴:賢いやり方で、mock後にインタフェースを呼び出すのは完全に透明で、入出力を準備して、テーブル駆動テストを通じて、各種の境界値をカバーすることができます.testでのみ使用でき、呼び出すたびにmock入出力が必要で、使用はやや煩雑です.
fake実装
fakeとは、シミュレーションの真の依存を簡略化し、外部システムの依存を遮断することを指す.
例:client-go fake client
Client-goはetcdに依存し、そのシミュレーションはfake-clientパッケージを実現し、メモリ内でリソースを追加削除して調べることを実現し、実際の依存etcd-clientと高度に一致している.
特徴:シミュレーションは符号化作業量が大きく、fakeコードも正確性を保証するためにテストする必要があるが、完備した後、使用が便利である.
統合テスト
テスト環境の実際の依存性を直接使用します.現在dockerなどのコンテナ技術による導入依存は非常に便利であり、データ初期化を行った後、テストコード接続テストdbを構成して統合テストを実行する.
docker-composeを使用してmysql,mongodb,etcdなどの依存をローカルに起動するには、私の別のプロジェクト:db-localを参照してください.
特徴:真実依存はオンライン環境と一致性が高く、バグを発見しやすい.しかし、比較的重く、起動が遅く、テストの実行時間が長い.