首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用gomock (或类似的)来模拟/验证对数据库的调用?

如何使用gomock (或类似的)来模拟/验证对数据库的调用?
EN

Stack Overflow用户
提问于 2020-08-28 03:30:35
回答 1查看 1.5K关注 0票数 0

转到这里,使用gorm to或/map to the DB (PSQL)。

我有以下代码:

代码语言:javascript
复制
package dbstuff

import (
    "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
}

我正在尝试为它编写一个单元测试,如下所示:

代码语言:javascript
复制
package dbstuff

import (
    "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)

}

当我运行它时,我得到无效的内存地址或空指针引用错误,因为我没有在我的OrderPersister实例上实例化一个设置*gorm.DB。有没有一种简单的方法来模拟/存根,这样我的测试就会确认我们试图查询orders表并返回或/映射结果?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-09-03 17:37:33

我将使用testify包为您的代码编写单元测试。为OrderPersister结构声明DB接口,而不是使用具体的类型*gorm.DB。由于我们不能在Go中模拟具体的类型及其方法。我们需要创建一个抽象层-- interface

63622995/db/db.go

代码语言:javascript
复制
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

代码语言:javascript
复制
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对象并将其传递给OrderPersister结构。

63622995/mocks/db.go

代码语言:javascript
复制
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

代码语言:javascript
复制
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")
    })
}

单元测试结果:

代码语言:javascript
复制
=== 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

覆盖范围报告:

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63622995

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档