go-sqlmock
go-sqlmock copied to clipboard
gorm (v1.22.4) problem
Hello,
I am having a problem when I working with gorm v2. I have tried every solution and I could find but none worked.
gorm version: 1.22.4 sqlmock version: v1.5.0
This is my code:
package repositories
import (
"balance-service/src/models"
"database/sql"
"log"
"regexp"
"github.com/DATA-DOG/go-sqlmock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
var _ = Describe("Repository", func() {
var repository *TableTests
var mock sqlmock.Sqlmock
BeforeEach(func() {
var db *sql.DB
var err error
db, mock, err = sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
Expect(err).ShouldNot(HaveOccurred())
gdb, err := gorm.Open(postgres.New(postgres.Config{
Conn: db,
}), &gorm.Config{})
Expect(err).ShouldNot(HaveOccurred())
repository = NewTSRepository(gdb)
})
AfterEach(func() {
err := mock.ExpectationsWereMet() // make sure all expectations were met
Expect(err).ShouldNot(HaveOccurred())
})
Context("CreateSubscription", func() {
var fakeSub *models.TableTest
BeforeEach(func() {
fakeSub = &models.TableTest{
ID: "123",
Name: "dudu",
}
})
It("save", func() {
const query = `
INSERT INTO "table_test" ("id","name")
VALUES"`
mock.MatchExpectationsInOrder(false)
mock.ExpectBegin()
mock.ExpectQuery(regexp.QuoteMeta(query)).
WithArgs("123", "dudu").
WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1))
mock.ExpectCommit()
log.Println(repository)
err := repository.CreateTS(fakeSub)
Expect(err).ShouldNot(HaveOccurred())
})
})
})
The error:
Unexpected error:
<*fmt.wrapError | 0xc00043fda0>: {
msg: "call to ExecQuery 'INSERT INTO \"table_tests\" (\"id\",\"name\") VALUES ($1,$2)' with args [{Name: Ordinal:1 Value:123} {Name: Ordinal:2 Value:dudu}] was not expected; call to Rollback transaction was not expected",
err: <*errors.errorString | 0xc00045dd60>{
s: "call to Rollback transaction was not expected",
},
}
call to ExecQuery 'INSERT INTO "table_tests" ("id","name") VALUES ($1,$2)' with args [{Name: Ordinal:1 Value:123} {Name: Ordinal:2 Value:dudu}] was not expected; call to Rollback transaction was not expected
occurred
Thanks
if you usesqlmock.QueryMatcherEqual
, may be you should trim space around expect query
const query = `
INSERT INTO "table_test" ("id","name")
VALUES"`
to
const query = `INSERT INTO "table_test" ("id","name") VALUES"`
Hello,
I am having a problem when I working with gorm v2. I have tried every solution and I could find but none worked.
gorm version: 1.22.4 sqlmock version: v1.5.0
This is my code:
package repositories import ( "balance-service/src/models" "database/sql" "log" "regexp" "github.com/DATA-DOG/go-sqlmock" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "gorm.io/driver/postgres" "gorm.io/gorm" ) var _ = Describe("Repository", func() { var repository *TableTests var mock sqlmock.Sqlmock BeforeEach(func() { var db *sql.DB var err error db, mock, err = sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) Expect(err).ShouldNot(HaveOccurred()) gdb, err := gorm.Open(postgres.New(postgres.Config{ Conn: db, }), &gorm.Config{}) Expect(err).ShouldNot(HaveOccurred()) repository = NewTSRepository(gdb) }) AfterEach(func() { err := mock.ExpectationsWereMet() // make sure all expectations were met Expect(err).ShouldNot(HaveOccurred()) }) Context("CreateSubscription", func() { var fakeSub *models.TableTest BeforeEach(func() { fakeSub = &models.TableTest{ ID: "123", Name: "dudu", } }) It("save", func() { const query = ` INSERT INTO "table_test" ("id","name") VALUES"` mock.MatchExpectationsInOrder(false) mock.ExpectBegin() mock.ExpectQuery(regexp.QuoteMeta(query)). WithArgs("123", "dudu"). WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1)) mock.ExpectCommit() log.Println(repository) err := repository.CreateTS(fakeSub) Expect(err).ShouldNot(HaveOccurred()) }) }) })
The error:
Unexpected error: <*fmt.wrapError | 0xc00043fda0>: { msg: "call to ExecQuery 'INSERT INTO \"table_tests\" (\"id\",\"name\") VALUES ($1,$2)' with args [{Name: Ordinal:1 Value:123} {Name: Ordinal:2 Value:dudu}] was not expected; call to Rollback transaction was not expected", err: <*errors.errorString | 0xc00045dd60>{ s: "call to Rollback transaction was not expected", }, } call to ExecQuery 'INSERT INTO "table_tests" ("id","name") VALUES ($1,$2)' with args [{Name: Ordinal:1 Value:123} {Name: Ordinal:2 Value:dudu}] was not expected; call to Rollback transaction was not expected occurred
Thanks
I have the same issue. Did you find a solution yet?
Interestingly it seems to be an issue if all fields are provided into the create function or there's something like created_at
which is set at DB level via defaults.
package gorm_test
import (
"regexp"
"testing"
"time"
"github.com/DATA-DOG/go-sqlmock"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type Promoter struct {
ID uuid.UUID `json:"id" gorm:"type:uuid"`
Name string `json:"name"`
// CreatedAt time.Time `json:"created_at" gorm:"default:CURRENT_TIMESTAMP"`
}
func TestDB(parentT *testing.T) {
parentT.Parallel()
sqlDB, mock, errSQLMock := sqlmock.New()
assert.Nil(parentT, errSQLMock)
db, errDB := gorm.Open(postgres.New(postgres.Config{Conn: sqlDB}), &gorm.Config{})
assert.Nil(parentT, errDB)
parentT.Run("Promoter", func(t *testing.T) {
promoterID := uuid.New()
name := "Promoter"
// this expects the default transaction to begin
mock.ExpectBegin()
// this is the query to be expected
mock.ExpectQuery(
regexp.QuoteMeta(`INSERT INTO "promoters" ("id","name") VALUES ($1,$2)`)).
WithArgs(promoterID, name).WillReturnRows(sqlmock.NewRows([]string{}))
// this expects the default transaction to commit
mock.ExpectCommit()
promoter := Promoter{
ID: promoterID,
Name: name,
}
err := db.Debug().Create(&promoter).Error
assert.Nil(t, err)
// ensure that all fields were set on the User object
assert.Equal(t, promoter.ID, promoterID)
assert.Equal(t, promoter.Name, name)
// ensure that all expectations are met in the mock
errExpectations := mock.ExpectationsWereMet()
assert.Nil(t, errExpectations)
})
}
Once I uncomment the
CreatedAt time.Time `json:"created_at" gorm:"default:CURRENT_TIMESTAMP"`
it works. And I don't know why that should change anything.
Please post some example code working on the Go Playground. Here is a template.
Hello, I am having a problem when I working with gorm v2. I have tried every solution and I could find but none worked. gorm version: 1.22.4 sqlmock version: v1.5.0 This is my code:
package repositories import ( "balance-service/src/models" "database/sql" "log" "regexp" "github.com/DATA-DOG/go-sqlmock" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "gorm.io/driver/postgres" "gorm.io/gorm" ) var _ = Describe("Repository", func() { var repository *TableTests var mock sqlmock.Sqlmock BeforeEach(func() { var db *sql.DB var err error db, mock, err = sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) Expect(err).ShouldNot(HaveOccurred()) gdb, err := gorm.Open(postgres.New(postgres.Config{ Conn: db, }), &gorm.Config{}) Expect(err).ShouldNot(HaveOccurred()) repository = NewTSRepository(gdb) }) AfterEach(func() { err := mock.ExpectationsWereMet() // make sure all expectations were met Expect(err).ShouldNot(HaveOccurred()) }) Context("CreateSubscription", func() { var fakeSub *models.TableTest BeforeEach(func() { fakeSub = &models.TableTest{ ID: "123", Name: "dudu", } }) It("save", func() { const query = ` INSERT INTO "table_test" ("id","name") VALUES"` mock.MatchExpectationsInOrder(false) mock.ExpectBegin() mock.ExpectQuery(regexp.QuoteMeta(query)). WithArgs("123", "dudu"). WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1)) mock.ExpectCommit() log.Println(repository) err := repository.CreateTS(fakeSub) Expect(err).ShouldNot(HaveOccurred()) }) }) })
The error:
Unexpected error: <*fmt.wrapError | 0xc00043fda0>: { msg: "call to ExecQuery 'INSERT INTO \"table_tests\" (\"id\",\"name\") VALUES ($1,$2)' with args [{Name: Ordinal:1 Value:123} {Name: Ordinal:2 Value:dudu}] was not expected; call to Rollback transaction was not expected", err: <*errors.errorString | 0xc00045dd60>{ s: "call to Rollback transaction was not expected", }, } call to ExecQuery 'INSERT INTO "table_tests" ("id","name") VALUES ($1,$2)' with args [{Name: Ordinal:1 Value:123} {Name: Ordinal:2 Value:dudu}] was not expected; call to Rollback transaction was not expected occurred
Thanks
I have the same issue. Did you find a solution yet?
Interestingly it seems to be an issue if all fields are provided into the create function or there's something like
created_at
which is set at DB level via defaults.package gorm_test import ( "regexp" "testing" "time" "github.com/DATA-DOG/go-sqlmock" "github.com/google/uuid" "github.com/stretchr/testify/assert" "gorm.io/driver/postgres" "gorm.io/gorm" ) type Promoter struct { ID uuid.UUID `json:"id" gorm:"type:uuid"` Name string `json:"name"` // CreatedAt time.Time `json:"created_at" gorm:"default:CURRENT_TIMESTAMP"` } func TestDB(parentT *testing.T) { parentT.Parallel() sqlDB, mock, errSQLMock := sqlmock.New() assert.Nil(parentT, errSQLMock) db, errDB := gorm.Open(postgres.New(postgres.Config{Conn: sqlDB}), &gorm.Config{}) assert.Nil(parentT, errDB) parentT.Run("Promoter", func(t *testing.T) { promoterID := uuid.New() name := "Promoter" // this expects the default transaction to begin mock.ExpectBegin() // this is the query to be expected mock.ExpectQuery( regexp.QuoteMeta(`INSERT INTO "promoters" ("id","name") VALUES ($1,$2)`)). WithArgs(promoterID, name).WillReturnRows(sqlmock.NewRows([]string{})) // this expects the default transaction to commit mock.ExpectCommit() promoter := Promoter{ ID: promoterID, Name: name, } err := db.Debug().Create(&promoter).Error assert.Nil(t, err) // ensure that all fields were set on the User object assert.Equal(t, promoter.ID, promoterID) assert.Equal(t, promoter.Name, name) // ensure that all expectations are met in the mock errExpectations := mock.ExpectationsWereMet() assert.Nil(t, errExpectations) }) }
Once I uncomment the
CreatedAt time.Time `json:"created_at" gorm:"default:CURRENT_TIMESTAMP"`
it works. And I don't know why that should change anything.
When you set defaults with the gorm struct tag, gorm does some things that you don't always expect. (https://github.com/go-gorm/gorm/blob/master/callbacks/create.go#L207-L295). The order of struct fields and the columns in the sql statement don't always line up, if the struct fields is nil it won't be passed as an argument to the query, and depending on your dialect it may change from an exec (requires sqlmock.ExpectExec) to a query (requires sqlmock.ExpectQuery) and the sql statement might have extra clauses added to it. (in sqlserver a default fields adds OUTPUT INSERTED."column_with_default_field"
to the sql statement). If you're using the regex matcher, try using a broad match like mock.ExpectQuery(INSERT INTO "promoters" (.+) VALUES (.+)
) WITHOUT the regexp.QuoteMeta (because (.+) literally matches on 1 or more of any character. If that matches then try mock.ExpectQuery(regexp.QuoteMeta(INSERT INTO "promoters" ("id","name") VALUES ($1,$2)
))
Also, don't use regexp.QuoteMeta with the sqlmock.QueryMatcherEqual matcher. That could also be the reason because QuoteMeta with quote your ()'s and that will never match exactly with the actual query.