Создание базы данных gorm с помощью go-sqlmock (ошибка во время выполнения)

# #go #go-gorm #go-sqlmock

Вопрос:

Краткие сведения

Я пытаюсь использовать go-sqlmock с gorm для тестирования. Я хочу написать тест для начальной миграции базы данных, но я попал panic: runtime error: invalid memory address or nil pointer dereference в точку, и у меня возникли проблемы с выяснением причины. Судя по стеку ошибок, я думаю, что это делает следующее утверждение: db.AutoMigrate(amp;models.User{}) . Я не уверен, почему, поскольку db к этому моменту он якобы успешно запущен и models.User определен и создан в качестве аргумента db.AutoMigrate . У меня такое чувство, что ошибка в mocks.NewDatabase функции, но я в растерянности.

Не уверен, есть ли у кого-нибудь время или желание взглянуть на соответствующий код и помочь мне? Я отметил в коде, где происходят сбои (они находятся в последних двух блоках кода). Дайте мне знать, если вам поможет какой-либо дополнительный контекст.

Соответствующий Код

проект/src/модели/models.go

 package models  import (  "time"   "github.com/google/uuid"  "gorm.io/gorm" )  type Base struct {  ID uuid.UUID `json:"-" gorm:"primaryKey;type:uuid;not null"`  CreatedAt time.Time `json:"-" gorm:"autoCreateTime"`  UpdatedAt time.Time `json:"-" gorm:"autoUpdateTime"`  DeletedAt gorm.DeletedAt `json:"-" gorm:"index"` }  type User struct {  Base  Name string `json:"-"`  Email string `json:"-" gorm:"unique_index:user_email_index"`  Password string `json:"-" gorm:"size:72"` }  

проект/src/издевается/база данных.go

 package mocks  import (  "project/src/models"  "log"   "github.com/DATA-DOG/go-sqlmock"  "gorm.io/driver/mysql"  "gorm.io/gorm" )  func NewDatabase() (*gorm.DB, sqlmock.Sqlmock) {   // get db and mock  sqlDB, mock, err := sqlmock.New(  sqlmock.QueryMatcherOption(sqlmock.QueryMatcherRegexp),  )  if err != nil {  log.Fatalf("[sqlmock new] %s", err)  }  defer sqlDB.Close()   // create dialector  dialector := mysql.New(mysql.Config{  Conn: sqlDB,  DriverName: "mysql",  })   // a SELECT VERSION() query will be run when gorm opens the database  // so we need to expect that here  columns := []string{"version"}  mock.ExpectQuery("SELECT VERSION()").WithArgs().WillReturnRows(  mock.NewRows(columns).FromCSVString("1"),  )   // open the database  db, err := gorm.Open(dialector, amp;gorm.Config{ PrepareStmt: true })  if err != nil {  log.Fatalf("[gorm open] %s", err)  }   return db, mock }  

project/src/database/init.go

 package database  import (  "project/src/models"   "gorm.io/gorm" )  // Init auto-migrates the DB. func Init(db *gorm.DB) {  // Migrate the schema  // this panics with  // panic: runtime error: invalid memory address or nil pointer dereference  // User is defined and instantiated here  db.AutoMigrate(amp;models.User{}) }  

Now the test:

project/src/database/init_test.go

 package database  import (  "project/src/mocks"  "testing" )  func TestInitMigratesDB(t *testing.T) {  db, mock := mocks.NewDatabase()  mock.ExpectExec("CREATE TABLE users(.*)")  mock.ExpectCommit()    // fails here  Init(db) }  

И журнал

 Running tool: /usr/local/go/bin/go test -timeout 30s -run ^TestInitMigratesDB$ project/src/database  --- FAIL: TestInitMigratesDB (0.00s) panic: runtime error: invalid memory address or nil pointer dereference  panic: runtime error: invalid memory address or nil pointer dereference [recovered]  panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x11ce22e]  goroutine 35 [running]: testing.tRunner.func1.2({0x1505320, 0x19bfb00})  /usr/local/go/src/testing/testing.go:1209  0x24e testing.tRunner.func1()  /usr/local/go/src/testing/testing.go:1212  0x218 panic({0x1505320, 0x19bfb00})  /usr/local/go/src/runtime/panic.go:1038  0x215 database/sql.(*Rows).close(0x0, {0x0, 0x0})  /usr/local/go/src/database/sql/sql.go:3267  0x8e database/sql.(*Rows).Close(0x1e)  /usr/local/go/src/database/sql/sql.go:3263  0x1d panic({0x1505320, 0x19bfb00})  /usr/local/go/src/runtime/panic.go:1038  0x215 database/sql.(*Rows).Next(0x0)  /usr/local/go/src/database/sql/sql.go:2944  0x27 database/sql.(*Row).Scan(0xc0000afbd8, {0xc0000efb38, 0x11, 0x1})  /usr/local/go/src/database/sql/sql.go:3333  0xb4 gorm.io/gorm/migrator.Migrator.CurrentDatabase({{0x0, 0xc000483350, {0x1659c58, 0xc00041a0f0}}})  /go/pkg/mod/gorm.io/gorm@v1.21.15/migrator/migrator.go:673  0x8d gorm.io/gorm/migrator.Migrator.HasTable.func1(0xc0000f8380)  /go/pkg/mod/gorm.io/gorm@v1.21.15/migrator/migrator.go:265  0x51 gorm.io/gorm/migrator.Migrator.RunWithValue({{0x80, 0xc000483260, {0x1659c58, 0xc00041a0f0}}}, {0x1512320, 0xc0004fe2a0}, 0xc0000efcb8)  /go/pkg/mod/gorm.io/gorm@v1.21.15/migrator/migrator.go:50  0x126 gorm.io/gorm/migrator.Migrator.HasTable({{0x0, 0xc000483260, {0x1659c58, 0xc00041a0f0}}}, {0x1512320, 0xc0004fe2a0})  /go/pkg/mod/gorm.io/gorm@v1.21.15/migrator/migrator.go:264  0xe8 gorm.io/gorm/migrator.Migrator.AutoMigrate({{0x0, 0xc000426f90, {0x1659c58, 0xc00041a0f0}}}, {0xc00040f690, 0x0, 0x0})  /go/pkg/mod/gorm.io/gorm@v1.21.15/migrator/migrator.go:92  0x127 gorm.io/gorm.(*DB).AutoMigrate(0x151a800, {0xc00040f690, 0x1, 0x1})  /go/pkg/mod/gorm.io/gorm@v1.21.15/migrator.go:26  0x43 project/src/database.Init(0xc00041c230)  /Projects/project/src/database/init.go:12  0x7b project/src/database.TestInitMigratesDB(0x0)  /Projects/project/src/database/init_test.go:12  0x5a testing.tRunner(0xc0003a21a0, 0x15b5328)  /usr/local/go/src/testing/testing.go:1259  0x102 created by testing.(*T).Run  /usr/local/go/src/testing/testing.go:1306  0x35a FAIL project/src/database 0.276s FAIL  

Ответ №1:

Понял это. Это был параметр конфигурации: amp;gorm.Config{ PrepareStmt: true } . Хотя это работает в рабочей среде, это не работает с sqlmock. Исправил это, изменив его на: amp;gorm.Config{} .