首頁  >  文章  >  後端開發  >  去模擬

去模擬

WBOY
WBOY原創
2024-07-31 09:16:32711瀏覽

Go mock

什麼是 Go 模擬

Go mock 是一個模擬框架,允許開發人員為我們的介面建立模擬結構並定義其行為。

例如,它可以幫助我們產生 Reponsitory 的模擬實現,並根據某些輸入定義預期輸出。

原始倉庫:https://github.com/golang/mock

現在它不再維護了,所以我們應該使用 https://github.com/uber-go/mock 來代替。

安裝

go install go.uber.org/mock/mockgen@latest

主要特點

  • 模擬產生:gomock 包含一個名為mockgen 的工具,可以自動產生介面的模擬實作。
  • 靈活的期望:使用 gomock,您可以對模擬物件的行為定義精確的期望,例如:
    • 它應該接收的參數
    • 以及它應該回傳的值
    • 應呼叫方法的具體次數、最小或最大次數

Mockgen指令

依照本文檔了解如何使用mockgen CLI:

https://github.com/uber-go/mock?tab=readme-ov-file#running-mockgen

用法

假設你有一個 IUserRepo 接口,其中包含一些方法:

ports.go

package user

type IUserRepo interface {
    GetUserByID(id int) (*User, error)
    Insert(user User) error
    Update(id int, user User) error
}

domain.go

package user

type User struct {
    ID   int
    Name string
}

service.go

package user

import "fmt"

type UserService struct {
    repo IUserRepo
}

var invalidUserIDError = fmt.Errorf("invalid user id")

func (u *UserService) Upsert(user User) error {
    if user.ID <= 0 {
        return invalidUserIDError
    }
    existingUser, err := u.repo.GetUserByID(user.ID)
    if err != nil {
        return err
    }
    if existingUser == nil {
        return u.repo.Insert(user)
    }

    return u.repo.Update(user.ID, user)
}

1。運行mockgen產生模擬實例

go run go.uber.org/mock/mockgen@latest -source=interface.go -destination=mock.go -package=user
  • source:指定包含Repository介面的檔案。
  • 目的地:指定將寫入生成的模擬程式碼的檔案。
  • package:指定產生的mock的套件名稱。

2。指定期望值

service_test.go

package user

import (
    "go.uber.org/mock/gomock"
    "github.com/stretchr/testify/assert"
    "testing"
)

func TestUpsertUser(t *testing.T) {
    mockCtl := gomock.NewController(t)
    defer mockCtl.Finish()

    tests := []struct {
        name                 string
        user                 User
        specifyFunctionCalls func(mock *MockIUserRepo)
        expectedError        error
    }{
        {
            user: User{ID: 1, Name: "User 1"},
            name: "Should insert",
            specifyFunctionCalls: func(mockRepo *MockIUserRepo) {
                mockRepo.EXPECT().GetUserByID(1).Return(nil, nil).Times(1)
                mockRepo.EXPECT().Insert(User{ID: 1, Name: "User 1"}).Return(nil).Times(1)
            },
        },
        {
            name: "User existed - Should update",
            user: User{ID: 1, Name: "New User Name"},
            specifyFunctionCalls: func(mockRepo *MockIUserRepo) {
                mockRepo.EXPECT().GetUserByID(1).Return(&User{ID: 1, Name: "User 1"}, nil).Times(1)
                mockRepo.EXPECT().Update(1, User{ID: 1, Name: "New User Name"}).Return(nil).Times(1)
            },
        },
        {
            expectedError: invalidUserIDError,
        },
    }

    for _, test := range tests {
        t.Run(test.name, func(t *testing.T) {
            mockRepo := NewMockIUserRepo(mockCtl)
            if test.specifyFunctionCalls != nil {
                test.specifyFunctionCalls(mockRepo)
            }
            userService := UserService{repo: mockRepo}
            err := userService.Upsert(test.user)
            assert.Equal(t, test.expectedError, err)
        })
    }
}

在上面的測試文件中:

  • specifyFunctionCalls 允許我們自訂模擬函數期望,必須呼叫哪些函數以及必須呼叫這些函數多少次。
  • 如果您嘗試在specifyFunctionCalls規格中新增冗餘函數(例如在第一個測試中新增mockRepo.EXPECT().Update(....)),您的測試將因錯誤而失敗:missing call( s) .
  • 如果您的服務呼叫尚未指定的函數,您的測試將因錯誤而失敗:沒有預期呼叫該接收者的「Insert」方法。

原始碼

https://github.com/huantt/gomock-demo

以上是去模擬的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
上一篇:Go 的單元測試下一篇:Go 的單元測試