6

I'm using Gorm with the postgresql driver. I try to mock a database insert with go-sqlmock:

type Test struct {
    FirstName string `json:"first_name"`
}

func (db *DB) CreateTest() (*Test, error) {
    test := Test{"c"}
    if result := db.Create(&test); result.Error != nil {
        return nil, result.Error
    }

    return &test, nil
}


func TestCreateUser(t *testing.T) {
    _, mock, _ := sqlmock.NewWithDSN("sqlmock_db_0")

    mockedGorm, _ := gorm.Open("sqlmock", "sqlmock_db_0")
    defer mockedGorm.Close()
    myDB := &DB{mockedGorm}

    mock.ExpectExec("INSERT INTO test").WithArgs("c").WillReturnResult(sqlmock.NewResult(1, 1))
    myDB.Exec("INSERT INTO test(first_name) VALUES (?)", "c")


    if _, err := myDB.CreateTest(); err != nil {
        t.Errorf("error was not expected: %s", err)
    }

    if err := mock.ExpectationsWereMet(); err != nil {
        t.Errorf("there were unfulfilled expectations: %s", err)
    }
}

Unfortunately, this gives me an error:

error was not expected: all expectations were already fulfilled, call to database transaction Begin was not expected

How do I test an insert with gorm, postgresql and sql-mock properly?

robbieperry22
  • 1,753
  • 1
  • 18
  • 49
user3255061
  • 1,757
  • 1
  • 30
  • 50
  • 2
    The error message is pretty explicit. "Begin was not expected". You didn't tell it to expect a Begin, which GORM is obviously executing. What help do you need? – Jonathan Hall Feb 10 '20 at 19:03
  • I don't know who downvoted your question, but all votes on SO are intentionally anonymous, and asking for anything else is inappropriate. – Jonathan Hall Feb 12 '20 at 10:07
  • Further, I already provided a comment explaining a possible reason for a downvote, so you already have a (possible) explanation, before you even asked. – Jonathan Hall Feb 12 '20 at 10:07
  • 2
    I never questioned anonymity, I just stated that I don't see any obvious reasons why my question was downvoted and will therefore not be able to improve it (or any future questions). And while it's true that the error message is pretty explicit and that you highlighted that in your comment, it was not so obvious to me. If it had been, I would not have to ask the question in the first place. But probably I should have made it clearer that I just began using go-sqlmock and Go. – user3255061 Feb 14 '20 at 21:24

1 Answers1

3

There were a couple of issues with my code:

1) As @flimzy pointed out rightfully, there has to be a ExpectBegin() (and ExpectCommit()) statement. This gets more obvious if one turns on the GORM debugger that shows what exactly GORM is doing.

2) ExpectExec("INSERT INTO test").WithArgs("c") does quite obviously not match myDB.Exec("INSERT INTO test(first_name) VALUES (?)", "c")

3) One has to escape the statement, as go-sqlmock takes a regex, here Go's https://godoc.org/regexp#QuoteMeta comes in handy.

Working code:

mock.ExpectBegin()
mock.ExpectExec(regexp.QuoteMeta("INSERT INTO \"tests\" (\"first_name\") VALUES (?)")).WithArgs("c").WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectCommit()
user3255061
  • 1,757
  • 1
  • 30
  • 50