tag | 35c1c6e210a3c38138135af2d95a66ee5109d071 | |
---|---|---|
tagger | gedi <gediminas.morkevicius@gmail.com> | Fri Aug 28 08:06:39 2015 |
object | febff80c09712044459f72847e56aaa69c9dad3b |
concurrency support and other known issues
commit | febff80c09712044459f72847e56aaa69c9dad3b | [log] [tgz] |
---|---|---|
author | gedi <gediminas.morkevicius@gmail.com> | Fri Aug 28 08:06:14 2015 |
committer | gedi <gediminas.morkevicius@gmail.com> | Fri Aug 28 08:06:14 2015 |
tree | d90c58b266410ed97369f2917948aee03f456725 | |
parent | 711064c51db37f1b2112a6bdb3839e72b2902b38 [diff] |
do not expose sql driver methods for sqlmock, give interface
This is a mock driver as database/sql/driver which is very flexible and pragmatic to manage and mock expected queries. All the expectations should be met and all queries and actions triggered should be mocked in order to pass a test. The package has no 3rd party dependencies.
NOTE: regarding major issues #20 and #9 the api has changed to support concurrency and more than one database connection.
If you need an old version, checkout go-sqlmock at gopkg.in:
go get gopkg.in/DATA-DOG/go-sqlmock.v0
Otherwise use the v1 branch from master which should be stable afterwards, because all the issues which were known will be fixed in this version.
go get gopkg.in/DATA-DOG/go-sqlmock.v1
Or take an older version:
go get gopkg.in/DATA-DOG/go-sqlmock.v0
Visit godoc for general examples and public api reference. See .travis.yml for supported go versions. Different use case, is to functionally test with a real database - go-txdb all database related actions are isolated within a single transaction so the database can remain in the same state.
See implementation examples:
package main import "database/sql" func recordStats(db *sql.DB, userID, productID int64) (err error) { tx, err := db.Begin() if err != nil { return } defer func() { switch err { case nil: err = tx.Commit() default: tx.Rollback() } }() if _, err = tx.Exec("UPDATE products SET views = views + 1"); err != nil { return } if _, err = tx.Exec("INSERT INTO product_viewers (user_id, product_id) VALUES (?, ?)", userID, productID); err != nil { return } return } func main() { // @NOTE: the real connection is not required for tests db, err := sql.Open("mysql", "root@/blog") if err != nil { panic(err) } defer db.Close() if err = recordStats(db, 1 /*some user id*/, 5 /*some product id*/); err != nil { panic(err) } }
package main import ( "fmt" "testing" "github.com/DATA-DOG/go-sqlmock" ) // a successful case func TestShouldUpdateStats(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() mock.ExpectBegin() mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() // now we execute our method if err = recordStats(db, 2, 3); err != nil { t.Errorf("error was not expected while updating stats: %s", err) } // we make sure that all expectations were met if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("there were unfulfilled expections: %s", err) } } // a failing test case func TestShouldRollbackStatUpdatesOnFailure(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() mock.ExpectBegin() mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectExec("INSERT INTO product_viewers"). WithArgs(2, 3). WillReturnError(fmt.Errorf("some error")) mock.ExpectRollback() // now we execute our method if err = recordStats(db, 2, 3); err == nil { t.Errorf("was expecting an error, but there was none") } // we make sure that all expectations were met if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("there were unfulfilled expections: %s", err) } }
go test -race
Feel free to open a pull request. Note, if you wish to contribute an extension to public (exported methods or types) - please open an issue before, to discuss whether these changes can be accepted. All backward incompatible changes are and will be treated cautiously