Golang中GORM单元测试失败问题排查
Golang中GORM单元测试失败问题排查 大家好, 我尝试为以下服务创建单元测试,但无法模拟GORM数据库。能否请您提供帮助?
服务:
package services
import (
"errors"
errorsconstant "paymentpoc/errors"
"paymentpoc/models"
"gorm.io/gorm"
)
func ProcessCreditTransaction(req models.PaymentRequest, DB *gorm.DB) error {
var payee models.Payee
if err := DB.Where("payee_id = ?", req.PayeeID).First(&payee).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errorsconstant.ErrPayerNotFound
}
return err
}
payee.Balance += req.Amount
if err := DB.Save(&payee).Error; err != nil {
return err
}
return nil
}
单元测试:
package services
import (
"testing"
errorsconstant "paymentpoc/errors"
"paymentpoc/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
_ "modernc.org/sqlite"
)
type ServicesSuite struct {
suite.Suite
DB *gorm.DB
}
func (suite *ServicesSuite) SetupTest() {
var err error
suite.DB, err = gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
if err != nil {
suite.T().Fatal("Failed to connect to database:", err)
}
// Auto migrate the schema
err = suite.DB.AutoMigrate(&models.Payee{})
if err != nil {
suite.T().Fatal("Failed to migrate database:", err)
}
}
func (suite *ServicesSuite) TearDownTest() {
// Clean up the database after each test
db, _ := suite.DB.DB()
db.Close()
}
func TestServicesSuite(t *testing.T) {
suite.Run(t, new(ServicesSuite))
}
func (suite *ServicesSuite) TestProcessCreditTransaction_Success() {
// Arrange
payee := models.Payee{
ID: "123", // 使用 `ID` 而非 `PayeeID`
Balance: 100.0,
}
suite.DB.Create(&payee)
req := models.PaymentRequest{PayeeID: "123", Amount: 50.0}
// Act
err := ProcessCreditTransaction(req, suite.DB)
// Assert
assert.NoError(suite.T(), err)
var updatedPayee models.Payee
// 改为使用 `id` 而非 `payee_id`
suite.DB.First(&updatedPayee, "id = ?", "123")
assert.Equal(suite.T(), 150.0, updatedPayee.Balance) // 期望更新后的余额为150
}
func (suite *ServicesSuite) TestProcessCreditTransaction_PayeeNotFound() {
// Arrange
req := models.PaymentRequest{PayeeID: "nonexistent", Amount: 50.0}
// Act
err := ProcessCreditTransaction(req, suite.DB)
// Assert
assert.Error(suite.T(), err)
assert.Equal(suite.T(), errorsconstant.ErrPayerNotFound, err)
}
更多关于Golang中GORM单元测试失败问题排查的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang中GORM单元测试失败问题排查的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
从你的代码来看,主要问题在于模型字段映射不匹配。服务代码中查询使用的是 payee_id 字段,但测试中创建的是 ID 字段。以下是修正后的单元测试:
package services
import (
"testing"
errorsconstant "paymentpoc/errors"
"paymentpoc/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
_ "modernc.org/sqlite"
)
type ServicesSuite struct {
suite.Suite
DB *gorm.DB
}
func (suite *ServicesSuite) SetupTest() {
var err error
suite.DB, err = gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
if err != nil {
suite.T().Fatal("Failed to connect to database:", err)
}
// Auto migrate the schema
err = suite.DB.AutoMigrate(&models.Payee{})
if err != nil {
suite.T().Fatal("Failed to migrate database:", err)
}
}
func (suite *ServicesSuite) TearDownTest() {
// Clean up the database after each test
db, _ := suite.DB.DB()
db.Close()
}
func TestServicesSuite(t *testing.T) {
suite.Run(t, new(ServicesSuite))
}
func (suite *ServicesSuite) TestProcessCreditTransaction_Success() {
// Arrange
payee := models.Payee{
PayeeID: "123", // 改为 PayeeID 以匹配服务中的查询条件
Balance: 100.0,
}
suite.DB.Create(&payee)
req := models.PaymentRequest{PayeeID: "123", Amount: 50.0}
// Act
err := ProcessCreditTransaction(req, suite.DB)
// Assert
assert.NoError(suite.T(), err)
var updatedPayee models.Payee
suite.DB.Where("payee_id = ?", "123").First(&updatedPayee)
assert.Equal(suite.T(), 150.0, updatedPayee.Balance)
}
func (suite *ServicesSuite) TestProcessCreditTransaction_PayeeNotFound() {
// Arrange
req := models.PaymentRequest{PayeeID: "nonexistent", Amount: 50.0}
// Act
err := ProcessCreditTransaction(req, suite.DB)
// Assert
assert.Error(suite.T(), err)
assert.Equal(suite.T(), errorsconstant.ErrPayerNotFound, err)
}
如果问题仍然存在,检查你的 models.Payee 结构体定义。确保 PayeeID 字段有正确的 GORM 标签:
type Payee struct {
PayeeID string `gorm:"column:payee_id;primaryKey"`
Balance float64 `gorm:"column:balance"`
}
另外,建议在测试中添加事务回滚,确保测试隔离:
func (suite *ServicesSuite) SetupTest() {
var err error
suite.DB, err = gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
if err != nil {
suite.T().Fatal("Failed to connect to database:", err)
}
// 开启事务
suite.DB = suite.DB.Begin()
// Auto migrate the schema
err = suite.DB.AutoMigrate(&models.Payee{})
if err != nil {
suite.T().Fatal("Failed to migrate database:", err)
}
}
func (suite *ServicesSuite) TearDownTest() {
// 回滚事务
suite.DB.Rollback()
db, _ := suite.DB.DB()
db.Close()
}

