package sqlmock import ( "database/sql" "fmt" "testing" "time" ) // test the case when db is not triggered and expectations // are not asserted on close func TestIssue4(t *testing.T) { db, err := New() if err != nil { t.Errorf("an error '%s' was not expected when opening a stub database connection", err) } ExpectQuery("some sql query which will not be called"). WillReturnRows(NewRows([]string{"id"})) err = db.Close() if err == nil { t.Errorf("Was expecting an error, since expected query was not matched") } } func TestMockQuery(t *testing.T) { db, err := sql.Open("mock", "") if err != nil { t.Errorf("an error '%s' was not expected when opening a stub database connection", err) } rs := NewRows([]string{"id", "title"}).FromCSVString("5,hello world") ExpectQuery("SELECT (.+) FROM articles WHERE id = ?"). WithArgs(5). WillReturnRows(rs) rows, err := db.Query("SELECT (.+) FROM articles WHERE id = ?", 5) if err != nil { t.Errorf("error '%s' was not expected while retrieving mock rows", err) } defer rows.Close() if !rows.Next() { t.Error("it must have had one row as result, but got empty result set instead") } var id int var title string err = rows.Scan(&id, &title) if err != nil { t.Errorf("error '%s' was not expected while trying to scan row", err) } if id != 5 { t.Errorf("expected mocked id to be 5, but got %d instead", id) } if title != "hello world" { t.Errorf("expected mocked title to be 'hello world', but got '%s' instead", title) } if err = db.Close(); err != nil { t.Errorf("error '%s' was not expected while closing the database", err) } } func TestMockQueryTypes(t *testing.T) { db, err := sql.Open("mock", "") if err != nil { t.Errorf("an error '%s' was not expected when opening a stub database connection", err) } columns := []string{"id", "timestamp", "sold"} timestamp := time.Now() rs := NewRows(columns) rs.AddRow(5, timestamp, true) ExpectQuery("SELECT (.+) FROM sales WHERE id = ?"). WithArgs(5). WillReturnRows(rs) rows, err := db.Query("SELECT (.+) FROM sales WHERE id = ?", 5) if err != nil { t.Errorf("error '%s' was not expected while retrieving mock rows", err) } defer rows.Close() if !rows.Next() { t.Error("it must have had one row as result, but got empty result set instead") } var id int var time time.Time var sold bool err = rows.Scan(&id, &time, &sold) if err != nil { t.Errorf("error '%s' was not expected while trying to scan row", err) } if id != 5 { t.Errorf("expected mocked id to be 5, but got %d instead", id) } if time != timestamp { t.Errorf("expected mocked time to be %s, but got '%s' instead", timestamp, time) } if sold != true { t.Errorf("expected mocked boolean to be true, but got %v instead", sold) } if err = db.Close(); err != nil { t.Errorf("error '%s' was not expected while closing the database", err) } } func TestTransactionExpectations(t *testing.T) { db, err := sql.Open("mock", "") if err != nil { t.Errorf("an error '%s' was not expected when opening a stub database connection", err) } // begin and commit ExpectBegin() ExpectCommit() tx, err := db.Begin() if err != nil { t.Errorf("an error '%s' was not expected when beginning a transaction", err) } err = tx.Commit() if err != nil { t.Errorf("an error '%s' was not expected when commiting a transaction", err) } // begin and rollback ExpectBegin() ExpectRollback() tx, err = db.Begin() if err != nil { t.Errorf("an error '%s' was not expected when beginning a transaction", err) } err = tx.Rollback() if err != nil { t.Errorf("an error '%s' was not expected when rolling back a transaction", err) } // begin with an error ExpectBegin().WillReturnError(fmt.Errorf("some err")) tx, err = db.Begin() if err == nil { t.Error("an error was expected when beginning a transaction, but got none") } if err = db.Close(); err != nil { t.Errorf("error '%s' was not expected while closing the database", err) } } func TestPrepareExpectations(t *testing.T) { db, err := sql.Open("mock", "") if err != nil { t.Errorf("an error '%s' was not expected when opening a stub database connection", err) } // no expectations, w/o ExpectPrepare() stmt, err := db.Prepare("SELECT (.+) FROM articles WHERE id = ?") if err != nil { t.Errorf("error '%s' was not expected while creating a prepared statement", err) } if stmt == nil { t.Errorf("stmt was expected while creating a prepared statement") } // expect something else, w/o ExpectPrepare() var id int var title string rs := NewRows([]string{"id", "title"}).FromCSVString("5,hello world") ExpectQuery("SELECT (.+) FROM articles WHERE id = ?"). WithArgs(5). WillReturnRows(rs) stmt, err = db.Prepare("SELECT (.+) FROM articles WHERE id = ?") if err != nil { t.Errorf("error '%s' was not expected while creating a prepared statement", err) } if stmt == nil { t.Errorf("stmt was expected while creating a prepared statement") } err = stmt.QueryRow(5).Scan(&id, &title) if err != nil { t.Errorf("error '%s' was not expected while retrieving mock rows", err) } // expect normal result ExpectPrepare() stmt, err = db.Prepare("SELECT (.+) FROM articles WHERE id = ?") if err != nil { t.Errorf("error '%s' was not expected while creating a prepared statement", err) } if stmt == nil { t.Errorf("stmt was expected while creating a prepared statement") } // expect error result ExpectPrepare().WillReturnError(fmt.Errorf("Some DB error occurred")) stmt, err = db.Prepare("SELECT (.+) FROM articles WHERE id = ?") if err == nil { t.Error("error was expected while creating a prepared statement") } if stmt != nil { t.Errorf("stmt was not expected while creating a prepared statement returning error") } if err = db.Close(); err != nil { t.Errorf("error '%s' was not expected while closing the database", err) } } func TestPreparedQueryExecutions(t *testing.T) { db, err := sql.Open("mock", "") if err != nil { t.Errorf("an error '%s' was not expected when opening a stub database connection", err) } rs1 := NewRows([]string{"id", "title"}).FromCSVString("5,hello world") ExpectQuery("SELECT (.+) FROM articles WHERE id = ?"). WithArgs(5). WillReturnRows(rs1) rs2 := NewRows([]string{"id", "title"}).FromCSVString("2,whoop") ExpectQuery("SELECT (.+) FROM articles WHERE id = ?"). WithArgs(2). WillReturnRows(rs2) stmt, err := db.Prepare("SELECT (.+) FROM articles WHERE id = ?") if err != nil { t.Errorf("error '%s' was not expected while creating a prepared statement", err) } var id int var title string err = stmt.QueryRow(5).Scan(&id, &title) if err != nil { t.Errorf("error '%s' was not expected querying row from statement and scanning", err) } if id != 5 { t.Errorf("expected mocked id to be 5, but got %d instead", id) } if title != "hello world" { t.Errorf("expected mocked title to be 'hello world', but got '%s' instead", title) } err = stmt.QueryRow(2).Scan(&id, &title) if err != nil { t.Errorf("error '%s' was not expected querying row from statement and scanning", err) } if id != 2 { t.Errorf("expected mocked id to be 2, but got %d instead", id) } if title != "whoop" { t.Errorf("expected mocked title to be 'whoop', but got '%s' instead", title) } if err = db.Close(); err != nil { t.Errorf("error '%s' was not expected while closing the database", err) } } func TestUnexpectedOperations(t *testing.T) { db, err := sql.Open("mock", "") if err != nil { t.Errorf("an error '%s' was not expected when opening a stub database connection", err) } stmt, err := db.Prepare("SELECT (.+) FROM articles WHERE id = ?") if err != nil { t.Errorf("error '%s' was not expected while creating a prepared statement", err) } var id int var title string err = stmt.QueryRow(5).Scan(&id, &title) if err == nil { t.Error("error was expected querying row, since there was no such expectation") } ExpectRollback() err = db.Close() if err == nil { t.Error("error was expected while closing the database, expectation was not fulfilled", err) } } func TestWrongExpectations(t *testing.T) { db, err := sql.Open("mock", "") if err != nil { t.Errorf("an error '%s' was not expected when opening a stub database connection", err) } ExpectBegin() rs1 := NewRows([]string{"id", "title"}).FromCSVString("5,hello world") ExpectQuery("SELECT (.+) FROM articles WHERE id = ?"). WithArgs(5). WillReturnRows(rs1) ExpectCommit().WillReturnError(fmt.Errorf("deadlock occured")) ExpectRollback() // won't be triggered stmt, err := db.Prepare("SELECT (.+) FROM articles WHERE id = ? FOR UPDATE") if err != nil { t.Errorf("error '%s' was not expected while creating a prepared statement", err) } var id int var title string err = stmt.QueryRow(5).Scan(&id, &title) if err == nil { t.Error("error was expected while querying row, since there begin transaction expectation is not fulfilled") } // lets go around and start transaction tx, err := db.Begin() if err != nil { t.Errorf("an error '%s' was not expected when beginning a transaction", err) } err = stmt.QueryRow(5).Scan(&id, &title) if err != nil { t.Errorf("error '%s' was not expected while querying row, since transaction was started", err) } err = tx.Commit() if err == nil { t.Error("a deadlock error was expected when commiting a transaction", err) } err = db.Close() if err == nil { t.Error("error was expected while closing the database, expectation was not fulfilled", err) } } func TestExecExpectations(t *testing.T) { db, err := sql.Open("mock", "") if err != nil { t.Errorf("an error '%s' was not expected when opening a stub database connection", err) } result := NewResult(1, 1) ExpectExec("^INSERT INTO articles"). WithArgs("hello"). WillReturnResult(result) res, err := db.Exec("INSERT INTO articles (title) VALUES (?)", "hello") if err != nil { t.Errorf("error '%s' was not expected, while inserting a row", err) } id, err := res.LastInsertId() if err != nil { t.Errorf("error '%s' was not expected, while getting a last insert id", err) } affected, err := res.RowsAffected() if err != nil { t.Errorf("error '%s' was not expected, while getting affected rows", err) } if id != 1 { t.Errorf("expected last insert id to be 1, but got %d instead", id) } if affected != 1 { t.Errorf("expected affected rows to be 1, but got %d instead", affected) } if err = db.Close(); err != nil { t.Errorf("error '%s' was not expected while closing the database", err) } } func TestRowBuilderAndNilTypes(t *testing.T) { db, err := sql.Open("mock", "") if err != nil { t.Errorf("an error '%s' was not expected when opening a stub database connection", err) } rs := NewRows([]string{"id", "active", "created", "status"}). AddRow(1, true, time.Now(), 5). AddRow(2, false, nil, nil) ExpectQuery("SELECT (.+) FROM sales").WillReturnRows(rs) rows, err := db.Query("SELECT * FROM sales") if err != nil { t.Errorf("error '%s' was not expected while retrieving mock rows", err) } defer rows.Close() // NullTime and NullInt are used from stubs_test.go var ( id int active bool created NullTime status NullInt ) if !rows.Next() { t.Error("it must have had row in rows, but got empty result set instead") } err = rows.Scan(&id, &active, &created, &status) if err != nil { t.Errorf("error '%s' was not expected while trying to scan row", err) } if id != 1 { t.Errorf("expected mocked id to be 1, but got %d instead", id) } if !active { t.Errorf("expected 'active' to be 'true', but got '%v' instead", active) } if !created.Valid { t.Errorf("expected 'created' to be valid, but it %+v is not", created) } if !status.Valid { t.Errorf("expected 'status' to be valid, but it %+v is not", status) } if status.Integer != 5 { t.Errorf("expected 'status' to be '5', but got '%d'", status.Integer) } // test second row if !rows.Next() { t.Error("it must have had row in rows, but got empty result set instead") } err = rows.Scan(&id, &active, &created, &status) if err != nil { t.Errorf("error '%s' was not expected while trying to scan row", err) } if id != 2 { t.Errorf("expected mocked id to be 2, but got %d instead", id) } if active { t.Errorf("expected 'active' to be 'false', but got '%v' instead", active) } if created.Valid { t.Errorf("expected 'created' to be invalid, but it %+v is not", created) } if status.Valid { t.Errorf("expected 'status' to be invalid, but it %+v is not", status) } if err = db.Close(); err != nil { t.Errorf("error '%s' was not expected while closing the database", err) } } func TestArgumentReflectValueTypeError(t *testing.T) { db, err := sql.Open("mock", "") if err != nil { t.Errorf("an error '%s' was not expected when opening a stub database connection", err) } rs := NewRows([]string{"id"}).AddRow(1) ExpectQuery("SELECT (.+) FROM sales").WithArgs(5.5).WillReturnRows(rs) _, err = db.Query("SELECT * FROM sales WHERE x = ?", 5) if err == nil { t.Error("Expected error, but got none") } }