mirror of
https://github.com/zhashkevych/go-sqlxmock.git
synced 2024-11-24 08:12:13 +02:00
197 lines
5.5 KiB
Go
197 lines
5.5 KiB
Go
/*
|
|
Package sqlmock provides sql driver mock connecection, which allows to test database,
|
|
create expectations and ensure the correct execution flow of any database operations.
|
|
It hooks into Go standard library's database/sql package.
|
|
|
|
The package provides convenient methods to mock database queries, transactions and
|
|
expect the right execution flow, compare query arguments or even return error instead
|
|
to simulate failures. See the example bellow, which illustrates how convenient it is
|
|
to work with:
|
|
|
|
|
|
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"github.com/DATA-DOG/go-sqlmock"
|
|
"testing"
|
|
"fmt"
|
|
)
|
|
|
|
// will test that order with a different status, cannot be cancelled
|
|
func TestShouldNotCancelOrderWithNonPendingStatus(t *testing.T) {
|
|
// open database stub
|
|
db, err := sql.Open("mock", "")
|
|
if err != nil {
|
|
t.Errorf("An error '%s' was not expected when opening a stub database connection", err)
|
|
}
|
|
|
|
// columns to be used for result
|
|
columns := []string{"id", "status"}
|
|
// expect transaction begin
|
|
sqlmock.ExpectBegin()
|
|
// expect query to fetch order, match it with regexp
|
|
sqlmock.ExpectQuery("SELECT (.+) FROM orders (.+) FOR UPDATE").
|
|
WithArgs(1).
|
|
WillReturnRows(sqlmock.NewRows(columns).FromCSVString("1,1"))
|
|
// expect transaction rollback, since order status is "cancelled"
|
|
sqlmock.ExpectRollback()
|
|
|
|
// run the cancel order function
|
|
someOrderId := 1
|
|
// call a function which executes expected database operations
|
|
err = cancelOrder(someOrderId, db)
|
|
if err != nil {
|
|
t.Errorf("Expected no error, but got %s instead", err)
|
|
}
|
|
// db.Close() ensures that all expectations have been met
|
|
if err = db.Close(); err != nil {
|
|
t.Errorf("Error '%s' was not expected while closing the database", err)
|
|
}
|
|
}
|
|
|
|
*/
|
|
package sqlmock
|
|
|
|
import (
|
|
"database/sql"
|
|
"database/sql/driver"
|
|
"fmt"
|
|
"regexp"
|
|
)
|
|
|
|
var mock *mockDriver
|
|
|
|
// Mock interface defines a mock which is returned
|
|
// by any expectation and can be detailed further
|
|
// with the methods this interface provides
|
|
type Mock interface {
|
|
WithArgs(...driver.Value) Mock
|
|
WillReturnError(error) Mock
|
|
WillReturnRows(driver.Rows) Mock
|
|
WillReturnResult(driver.Result) Mock
|
|
}
|
|
|
|
type mockDriver struct {
|
|
conn *conn
|
|
}
|
|
|
|
func (d *mockDriver) Open(dsn string) (driver.Conn, error) {
|
|
return mock.conn, nil
|
|
}
|
|
|
|
func init() {
|
|
mock = &mockDriver{&conn{}}
|
|
sql.Register("mock", mock)
|
|
}
|
|
|
|
// New creates sqlmock database connection
|
|
// and pings it so that all expectations could be
|
|
// asserted on Close.
|
|
func New() (db *sql.DB, err error) {
|
|
db, err = sql.Open("mock", "")
|
|
if err != nil {
|
|
return
|
|
}
|
|
// ensure open connection, otherwise Close does not assert expectations
|
|
db.Ping()
|
|
return
|
|
}
|
|
|
|
// ExpectBegin expects transaction to be started
|
|
func ExpectBegin() Mock {
|
|
e := &expectedBegin{}
|
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
|
mock.conn.active = e
|
|
return mock.conn
|
|
}
|
|
|
|
// ExpectCommit expects transaction to be commited
|
|
func ExpectCommit() Mock {
|
|
e := &expectedCommit{}
|
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
|
mock.conn.active = e
|
|
return mock.conn
|
|
}
|
|
|
|
// ExpectRollback expects transaction to be rolled back
|
|
func ExpectRollback() Mock {
|
|
e := &expectedRollback{}
|
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
|
mock.conn.active = e
|
|
return mock.conn
|
|
}
|
|
|
|
// ExpectPrepare expects Query to be prepared
|
|
func ExpectPrepare() Mock {
|
|
e := &expectedPrepare{}
|
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
|
mock.conn.active = e
|
|
return mock.conn
|
|
}
|
|
|
|
// WillReturnError the expectation will return an error
|
|
func (c *conn) WillReturnError(err error) Mock {
|
|
c.active.setError(err)
|
|
return c
|
|
}
|
|
|
|
// ExpectExec expects database Exec to be triggered, which will match
|
|
// the given query string as a regular expression
|
|
func ExpectExec(sqlRegexStr string) Mock {
|
|
e := &expectedExec{}
|
|
e.sqlRegex = regexp.MustCompile(sqlRegexStr)
|
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
|
mock.conn.active = e
|
|
return mock.conn
|
|
}
|
|
|
|
// ExpectQuery database Query to be triggered, which will match
|
|
// the given query string as a regular expression
|
|
func ExpectQuery(sqlRegexStr string) Mock {
|
|
e := &expectedQuery{}
|
|
e.sqlRegex = regexp.MustCompile(sqlRegexStr)
|
|
|
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
|
mock.conn.active = e
|
|
return mock.conn
|
|
}
|
|
|
|
// WithArgs expectation should be called with given arguments.
|
|
// Works with Exec and Query expectations
|
|
func (c *conn) WithArgs(args ...driver.Value) Mock {
|
|
eq, ok := c.active.(*expectedQuery)
|
|
if !ok {
|
|
ee, ok := c.active.(*expectedExec)
|
|
if !ok {
|
|
panic(fmt.Sprintf("arguments may be expected only with query based expectations, current is %T", c.active))
|
|
}
|
|
ee.args = args
|
|
} else {
|
|
eq.args = args
|
|
}
|
|
return c
|
|
}
|
|
|
|
// WillReturnResult expectation will return a Result.
|
|
// Works only with Exec expectations
|
|
func (c *conn) WillReturnResult(result driver.Result) Mock {
|
|
eq, ok := c.active.(*expectedExec)
|
|
if !ok {
|
|
panic(fmt.Sprintf("driver.result may be returned only by exec expectations, current is %T", c.active))
|
|
}
|
|
eq.result = result
|
|
return c
|
|
}
|
|
|
|
// WillReturnRows expectation will return Rows.
|
|
// Works only with Query expectations
|
|
func (c *conn) WillReturnRows(rows driver.Rows) Mock {
|
|
eq, ok := c.active.(*expectedQuery)
|
|
if !ok {
|
|
panic(fmt.Sprintf("driver.rows may be returned only by query expectations, current is %T", c.active))
|
|
}
|
|
eq.rows = rows
|
|
return c
|
|
}
|