亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何使用 gomock (或類似的)來模擬/驗證對數據庫的調用?

如何使用 gomock (或類似的)來模擬/驗證對數據庫的調用?

Go
呼如林 2022-06-27 15:00:01
轉到這里,使用gorm或/映射到數據庫 (PSQL)。我有以下代碼:package dbstuffimport (    "errors"  "github.com/google/uuid"  "github.com/jinzhu/gorm"    _ "github.com/jinzhu/gorm/dialects/postgres")type OrderPersister struct {        db *gorm.DB}func (p *OrderPersister) GetOrder(id uuid.UUID) (*Order, error) {        ret := &Order{}        err := p.db.Table("orders").Where("order_id = ?", id).Scan(ret).Error        return ret, err}我正在嘗試為它編寫一個單元測試,如下所示:package dbstuffimport (    "testing"  "errors"  "github.com/stretchr/testify/assert")func TestErrInternalServerError(t *testing.T) {  // given  id := uuid.New()  op := OrderPersister{}  // when  order, err := op.GetOrder(id)  // then  assert.NotNil(t, order)  assert.NotNil(t, err)}當我運行它時,我得到無效的內存地址或 nil 指針取消引用錯誤,因為我沒有*gorm.DB在我的OrderPersister實例上實例化設置 a。有沒有一種簡單的方法來模擬/存根,以便我的測試確認我們嘗試查詢orders表并返回或/映射結果?
查看完整描述

1 回答

?
慕桂英4014372

TA貢獻1871條經驗 獲得超13個贊

我將使用testify包為您的代碼編寫單元測試。而不是使用具體類型,而是為struct*gorm.DB聲明 DB 接口。OrderPersister由于我們不能在 Go 中模擬具體類型及其方法。我們需要創建一個抽象層—— interface.


63622995/db/db.go:


package db


type OrmDBWithError struct {

    OrmDB

    Error error

}


type OrmDB interface {

    Table(name string) OrmDB

    Where(query interface{}, args ...interface{}) OrmDB

    Scan(dest interface{}) *OrmDBWithError

}

63622995/main.go:


package main


import (

    "github.com/google/uuid"

    _ "github.com/jinzhu/gorm/dialects/postgres"

    "github.com/mrdulin/golang/src/stackoverflow/63622995/db"

)


type Order struct {

    order_id string

}


type OrderPersister struct {

    DB db.OrmDB

    //DB *gorm.DB

}


func (p *OrderPersister) GetOrder(id uuid.UUID) (*Order, error) {

    ret := &Order{}


    err := p.DB.Table("orders").Where("order_id = ?", id).Scan(ret).Error

    return ret, err

}

OrmDB為實現接口的 db 創建了模擬對象。然后,您可以創建此模擬 DB 對象并將其傳遞給OrderPersisterstruct。


63622995/mocks/db.go:


package mocks


import (

    "github.com/mrdulin/golang/src/stackoverflow/63622995/db"

    "github.com/stretchr/testify/mock"

)


type MockedOrmDB struct {

    mock.Mock

}


func (s *MockedOrmDB) Table(name string) db.OrmDB {

    args := s.Called(name)

    return args.Get(0).(db.OrmDB)

}


func (s *MockedOrmDB) Where(query interface{}, args ...interface{}) db.OrmDB {

    arguments := s.Called(query, args)

    return arguments.Get(0).(db.OrmDB)

}


func (s *MockedOrmDB) Scan(dest interface{}) *db.OrmDBWithError {

    args := s.Called(dest)

    return args.Get(0).(*db.OrmDBWithError)

}

63622995/main_test.go:


package main


import (

    "testing"


    "github.com/google/uuid"

    "github.com/mrdulin/golang/src/stackoverflow/63622995/db"

    "github.com/mrdulin/golang/src/stackoverflow/63622995/mocks"

    "github.com/stretchr/testify/assert"

    "github.com/stretchr/testify/mock"

)


func TestOrderPersister_GetOrder(t *testing.T) {

    assert := assert.New(t)

    t.Run("should get order", func(t *testing.T) {

        testDb := new(mocks.MockedOrmDB)

        id := uuid.New()

        testDb.

            On("Table", "orders").

            Return(testDb).

            On("Where", "order_id = ?", mock.Anything).

            Return(testDb).

            On("Scan", mock.Anything).Run(func(args mock.Arguments) {

            ret := args.Get(0).(*Order)

            ret.order_id = "123"

        }).

            Return(&db.OrmDBWithError{Error: nil})

        op := OrderPersister{DB: testDb}

        got, err := op.GetOrder(id)

        testDb.AssertExpectations(t)

        assert.Nil(err)

        assert.Equal(Order{order_id: "123"}, *got)

    })


    t.Run("should return error", func(t *testing.T) {

        testDb := new(mocks.MockedOrmDB)

        id := uuid.New()

        testDb.

            On("Table", "orders").

            Return(testDb).

            On("Where", "order_id = ?", mock.Anything).

            Return(testDb).

            On("Scan", mock.Anything).

            Return(&db.OrmDBWithError{Error: errors.New("network")})

        op := OrderPersister{DB: testDb}

        got, err := op.GetOrder(id)

        testDb.AssertExpectations(t)

        assert.Equal(Order{}, *got)

        assert.Equal(err.Error(), "network")

    })

}

單元測試結果:


=== RUN   TestOrderPersister_GetOrder

=== RUN   TestOrderPersister_GetOrder/should_get_order

    TestOrderPersister_GetOrder/should_get_order: main_test.go:32: PASS:    Table(string)

    TestOrderPersister_GetOrder/should_get_order: main_test.go:32: PASS:    Where(string,string)

    TestOrderPersister_GetOrder/should_get_order: main_test.go:32: PASS:    Scan(string)

=== RUN   TestOrderPersister_GetOrder/should_return_error

    TestOrderPersister_GetOrder/should_return_error: main_test.go:49: PASS: Table(string)

    TestOrderPersister_GetOrder/should_return_error: main_test.go:49: PASS: Where(string,string)

    TestOrderPersister_GetOrder/should_return_error: main_test.go:49: PASS: Scan(string)

--- PASS: TestOrderPersister_GetOrder (0.00s)

    --- PASS: TestOrderPersister_GetOrder/should_get_order (0.00s)

    --- PASS: TestOrderPersister_GetOrder/should_return_error (0.00s)

PASS


Process finished with exit code 0

覆蓋報告:

http://img1.sycdn.imooc.com//62b9559f00014b2b15990968.jpg

查看完整回答
反對 回復 2022-06-27
  • 1 回答
  • 0 關注
  • 154 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號