Mokeryを使った模擬データベースユニットテスト
9429 ワード
導入
皆さん、この記事では、プロジェクトの依存性をテストするためにmockeryを使用して、Goで単位テストを作成する方法を学びます.私たちは多くの場合、モジュールのような別の依存関係を持つ関数をテストするために模擬テストを使用するので、私たちはどのようにリファクタリングを作成し、ユニットテストを作成し、mockery自体を使用して、手順でステップで書いた例を使用して作成する方法を学ぶことが、それを開始しよう!
なぜモックリー?
mockeryはmock関数を生成するコマンドを用意しています.これは単体テストのために使うことができますので、結果としてmock関数をゼロから書く必要はありません
このチュートリアルをより簡単にするために、我々は最初の記事から最初に我々のコードをリファクタリングする準備をします
リファクタ
まず第一に、我々は古いコードを見に行くつもりです、我々はそれのインターフェースを定義するつもりです、どのように我々はそれをしますか?名前の新しいルートフォルダを作成することによって
repository
, ここから、私たちがデータベース依存関係を使用するとき、これは私たちが呼ぶものです.- config
|_ config.go
- models
|_ payment.go
- repository
|_ payment.go
- test.go
インターフェイスを定義することから始めますpayment.go
リポジトリフォルダ内type IPaymentRepository interface {
UpdatePayment(id string, payment models.Payment) (models.Payment, error)
DeletePayment(id string) (int64, error)
SelectPaymentWIthId(id string) (models.Payment, error)
CreatePayment(payment models.Payment) (int64, error)
}
データベース依存性を関数から分離するために、データベース依存関係を保持するためにtype Repository struct {
Database *gorm.DB
}
それから、我々はメインのもの以外のすべての機能を動かしますpayment.go
, 完全なリポジトリは次のようになりますpackage repository
import (
"errors"
"github.com/yanoandri/simple-goorm/models"
"gorm.io/gorm"
)
type IPaymentRepository interface {
UpdatePayment(id string, payment models.Payment) (models.Payment, error)
DeletePayment(id string) (int64, error)
SelectPaymentWIthId(id string) (models.Payment, error)
CreatePayment(payment models.Payment) (int64, error)
}
type Repository struct {
Database *gorm.DB
}
func (repo Repository) UpdatePayment(id string, payment models.Payment) (models.Payment, error) {
var updatePayment models.Payment
result := repo.Database.Model(&updatePayment).Where("id = ?", id).Updates(payment)
if result.RowsAffected == 0 {
return models.Payment{}, errors.New("payment data not update")
}
return updatePayment, nil
}
func (repo Repository) DeletePayment(id string) (int64, error) {
var deletedPayment models.Payment
result := repo.Database.Where("id = ?", id).Delete(&deletedPayment)
if result.RowsAffected == 0 {
return 0, errors.New("payment data not update")
}
return result.RowsAffected, nil
}
func (repo Repository) SelectPaymentWIthId(id string) (models.Payment, error) {
var payment models.Payment
result := repo.Database.First(&payment, "id = ?", id)
if result.RowsAffected == 0 {
return models.Payment{}, errors.New("payment data not found")
}
return payment, nil
}
func (repo Repository) CreatePayment(payment models.Payment) (int64, error) {
result := repo.Database.Create(&payment)
if result.RowsAffected == 0 {
return 0, errors.New("payment not created")
}
return result.RowsAffected, nil
}
すべての関数をリポジトリフォルダーに移動させるので、関数を呼び出す方法を変更する必要がありますtest.go
でmain
機能repo := repository.Repository{Database: db}
そして、そこから、我々のパラメタの中にどんな外部の依存関係も置くことなく、我々の機能を使うことができます// create a payment
payment := models.Payment{
PaymentCode: "XXX-1",
Name: "Payment for item #1",
Status: "PENDING",
}
result, err := repo.CreatePayment(payment)
単体テストファイルの作成
幸いにもVSCodeを使用する場合は、プレスによって自動的にユニットテストを生成できます
ctrl + p
場合は、Windowsまたはcommand + p
そして、あなたは以下のスクリーンショットのような機能を生成するオプションを見つけるでしょうそして、この例では、
CreatePayment
関数全体をブロックして生成するpackage repository
import (
"testing"
"github.com/yanoandri/simple-goorm/models"
)
func TestRepository_CreatePayment(t *testing.T) {
type args struct {
payment models.Payment
}
tests := []struct {
name string
repo Repository
args args
want int64
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.repo.CreatePayment(tt.args.payment)
if (err != nil) != tt.wantErr {
t.Errorf("Repository.CreatePayment() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("Repository.CreatePayment() = %v, want %v", got, tt.want)
}
})
}
}
模擬
我々は、コマンドを使用してmockeryをインストールします
go install github.com/vektra/mockery/v2@latest
それが終了した後、我々は、このコマンドを入力することにより、すべての機能の塊を生成するためにmockery機能を使用して我々の模擬機能を作成しますmockery --all --keeptree
注意mocks
当社のプロジェクトのフォルダがインストールされており、すべての機能がモックされているそして、これは我々の1つの例です
CreatePayment
模擬関数// CreatePayment provides a mock function with given fields: payment
func (_m *IPaymentRepository) CreatePayment(payment models.Payment) (int64, error) {
ret := _m.Called(payment)
var r0 int64
if rf, ok := ret.Get(0).(func(models.Payment) int64); ok {
r0 = rf(payment)
} else {
r0 = ret.Get(0).(int64)
}
var r1 error
if rf, ok := ret.Get(1).(func(models.Payment) error); ok {
r1 = rf(payment)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
我々のテスト機能を書く
我々のユニットテストに我々のmockked機能を含めましょう
package repository
import (
"errors"
"testing"
mocks "github.com/yanoandri/simple-goorm/mocks/repository"
"github.com/yanoandri/simple-goorm/models"
)
func TestRepository_CreatePayment(t *testing.T) {
type args struct {
payment models.Payment
}
tests := []struct {
name string
args args
want int64
wantErr bool
}{
// TODO: Add test cases.
{
name: "success_create_payment",
args: args{
models.Payment{
PaymentCode: "payment-code-011",
Status: "PENDING",
},
},
want: 1,
wantErr: false,
},
{
name: "failed_create_payment",
args: args{
models.Payment{},
},
want: 0,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
repo := &mocks.IPaymentRepository{}
if !tt.wantErr {
repo.On("CreatePayment", tt.args.payment).Return(tt.want, nil)
} else {
repo.On("CreatePayment", tt.args.payment).Return(tt.want, errors.New("Failed to create payment"))
}
got, err := repo.CreatePayment(tt.args.payment)
if (err != nil) != tt.wantErr {
t.Errorf("Repository.CreatePayment() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("Repository.CreatePayment() = %v, want %v", got, tt.want)
}
})
}
}
Repoが不足していることに注意してください.データベースの実際の依存関係を使用する必要がなかったからです.そして今のところコマンドを使ってテストを実行しますgo test ./... -v
結論
これは単体テストでmocks関数を使用する例として1つの関数です
UpdatePayment
, DeletePayment
そしてSelectPaymentWIthId
. Mockery我々の機能を生成するための簡単な方法を提供しており、結果として我々は2回から同じ機能を作成せずに我々の依存関係をテストすることができます、このチュートリアルを支援し、探索を維持!yaを参照してください!ソース
Repo
Reference
この問題について(Mokeryを使った模擬データベースユニットテスト), 我々は、より多くの情報をここで見つけました https://dev.to/yanoandri/mock-database-unit-test-with-mockery-in-go-42clテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol