Golang GORM DB模拟

xfyts7mz  于 2023-01-28  发布在  Go
关注(0)|答案(3)|浏览(208)

我必须模拟测试一个service.to创建新的服务,我需要通过gorm.DB{},但每次我通过它并运行测试,我得到零指针错误(恐慌)。请帮助如何模拟gorm.DB{}示例正确的单元测试。

func NewService(db *gorm.DB) Service {
    return &service{
        repo:  newReactionRepo(db),
    }
}

在测试中进行模拟调用,如下所示:

mockDB = &gorm.DB{}

package.NewService(mockDB)

获取此错误

testing.tRunner.func1.2({0x1648e40, 0x21cdd60})
    C:/Program Files/Go/src/testing/testing.go:1396 +0x24e
testing.tRunner.func1()
    C:/Program Files/Go/src/testing/testing.go:1399 +0x39f
panic({0x1648e40, 0x21cdd60})
    C:/Program Files/Go/src/runtime/panic.go:884 +0x212
gorm.io/gorm.(*DB).Session(0x21ef260, 0xc000861a50)
    C:/Users/acb/sdk/go1.17/pkg/mod/gorm.io/gorm@v1.24.2/gorm.go:215 +0x3b
gorm.io/gorm.(*DB).WithContext(...)
xienkqul

xienkqul1#

您可以初始化数据库,即:

//...
 mockDB := initDb()
 package.NewService(mockDB)
//...

func initDb() *gorm.DB {
    dsn := "host=localhost user=myuser password=mypassword dbname=mydb port=5432 sslmode=disable"

    db, err := gorm.Open(postgres.Open(dsn))
    if err != nil {
        log.Fatal("couldn't connect to db")
    }
    return db
}
6za6bjd0

6za6bjd02#

由于gorm.DB类型是一个结构体,这使得直接用它进行单元测试有点困难。对于你所得到的nil指针错误,你可能需要修改你的代码来检查传入的nil值,这样它就不会试图调用nil指针上的方法。
如果要进行单元测试,可以将数据库操作 Package 在接口中,然后提供不使用真实数据库的模拟实现。这可以通过以下方法实现:创建一个定义与数据库交互所需方法的接口,然后创建一个为实际数据库操作实现此接口的结构。
例如:

// Database is an interface that defines methods for interacting with a database.
type Database interface {
    Create(data interface{}) error
    GetByID(id int, result interface{}) error
}

// RealDatabase is a struct that implements the Database interface
// using a real GORM connection.
type RealDatabase struct {
    // db is a connection to the database
    db *gorm.DB
}

// Create saves the data in the database
func (rdb *RealDatabase) Create(data interface{}) error {
    return rdb.db.Create(data).Error
}

// GetByID retrieves the data by ID from the database
func (rdb *RealDatabase) GetByID(id int, result interface{}) error {
    return rdb.db.First(result, id).Error
}

// MockDatabase is a struct that implements the Database interface
// using a mock GORM connection.
type MockDatabase struct {
    // data is a map of ID to data used for mocking.
    data map[int]interface{}
}

// Create does not do anything but returns no errors
func (mdb *MockDatabase) Create(data interface{}) error {
    return nil
}

// GetByID returns the data for a given ID
func (mdb *MockDatabase) GetByID(id int, result interface{}) error {
    data, ok := mdb.data[id]
    if !ok {
        return fmt.Errorf("data not found for ID: %d", id)
    }
    result = data
    return nil
}

在此示例中,RealDatabase结构使用GORM与数据库交互,而MockDatabase结构使用Map来模拟真实数据库的行为。MockDatabase结构中的Create方法不执行任何操作,也不返回任何错误,GetByID方法返回给定ID的数据。您还可以根据需要向模拟结构和接口添加更多功能,以模拟真实数据库的行为。
最后,您还可以使用Gomock library,它提供的工具可以自动生成您提供给它的接口的模拟版本。

gudnpqoy

gudnpqoy3#

你可以试试用构图。

type DBInstance struct {
  *gorm.DB
}

DBInstance的示例传递给NewService(db DBInstance)而不是*gorm.DB。可以模拟在对代码进行单元测试时使用的*gorm.DB的方法。示例:

func (DBInstance) Find(dest interface{}, conds ...interface{}) (tx *DB) {
  // mock implementation of gorm.DB.Find()
}

从实际代码调用时,使用db示例初始化DB示例:

dsn := "host=localhost user=myuser password=mypassword dbname=mydb port=5432 sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn))
dbInstance := DBInstance{
  &db,
}

从单元测试调用时,传递一个未初始化的空*gorm.DB对象,并模拟所有必需的方法。

dbInstance := DBInstance{
  &gorm.DB{},
}

相关问题