Sql mock driver for golang to test database interactions

Overview

Build Status GoDoc Go Report Card codecov.io

Sql driver mock for Golang

sqlmock is a mock library implementing sql/driver. Which has one and only purpose - to simulate any sql driver behavior in tests, without needing a real database connection. It helps to maintain correct TDD workflow.

  • this library is now complete and stable. (you may not find new changes for this reason)
  • supports concurrency and multiple connections.
  • supports go1.8 Context related feature mocking and Named sql parameters.
  • does not require any modifications to your source code.
  • the driver allows to mock any sql driver method behavior.
  • has strict by default expectation order matching.
  • has no third party dependencies.

NOTE: in v1.2.0 sqlmock.Rows has changed to struct from interface, if you were using any type references to that interface, you will need to switch it to a pointer struct type. Also, sqlmock.Rows were used to implement driver.Rows interface, which was not required or useful for mocking and was removed. Hope it will not cause issues.

Looking for maintainers

I do not have much spare time for this library and willing to transfer the repository ownership to person or an organization motivated to maintain it. Open up a conversation if you are interested. See #230.

Install

go get github.com/DATA-DOG/go-sqlmock

Documentation and Examples

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:

Something you may want to test, assuming you use the go-mysql-driver

package main

import (
	"database/sql"

	_ "github.com/go-sql-driver/mysql"
)

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", "[email protected]/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)
	}
}

Tests with sqlmock

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 expectations: %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 expectations: %s", err)
	}
}

Customize SQL query matching

There were plenty of requests from users regarding SQL query string validation or different matching option. We have now implemented the QueryMatcher interface, which can be passed through an option when calling sqlmock.New or sqlmock.NewWithDSN.

This now allows to include some library, which would allow for example to parse and validate mysql SQL AST. And create a custom QueryMatcher in order to validate SQL in sophisticated ways.

By default, sqlmock is preserving backward compatibility and default query matcher is sqlmock.QueryMatcherRegexp which uses expected SQL string as a regular expression to match incoming query string. There is an equality matcher: QueryMatcherEqual which will do a full case sensitive match.

In order to customize the QueryMatcher, use the following:

	db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))

The query matcher can be fully customized based on user needs. sqlmock will not provide a standard sql parsing matchers, since various drivers may not follow the same SQL standard.

Matching arguments like time.Time

There may be arguments which are of struct type and cannot be compared easily by value like time.Time. In this case sqlmock provides an Argument interface which can be used in more sophisticated matching. Here is a simple example of time argument matching:

type AnyTime struct{}

// Match satisfies sqlmock.Argument interface
func (a AnyTime) Match(v driver.Value) bool {
	_, ok := v.(time.Time)
	return ok
}

func TestAnyTimeArgument(t *testing.T) {
	t.Parallel()
	db, mock, err := New()
	if err != nil {
		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
	}
	defer db.Close()

	mock.ExpectExec("INSERT INTO users").
		WithArgs("john", AnyTime{}).
		WillReturnResult(NewResult(1, 1))

	_, err = db.Exec("INSERT INTO users(name, created_at) VALUES (?, ?)", "john", time.Now())
	if err != nil {
		t.Errorf("error '%s' was not expected, while inserting a row", err)
	}

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

It only asserts that argument is of time.Time type.

Run tests

go test -race

Change Log

  • 2019-04-06 - added functionality to mock a sql MetaData request
  • 2019-02-13 - added go.mod removed the references and suggestions using gopkg.in.
  • 2018-12-11 - added expectation of Rows to be closed, while mocking expected query.
  • 2018-12-11 - introduced an option to provide QueryMatcher in order to customize SQL query matching.
  • 2017-09-01 - it is now possible to expect that prepared statement will be closed, using ExpectedPrepare.WillBeClosed.
  • 2017-02-09 - implemented support for go1.8 features. Rows interface was changed to struct but contains all methods as before and should maintain backwards compatibility. ExpectedQuery.WillReturnRows may now accept multiple row sets.
  • 2016-11-02 - db.Prepare() was not validating expected prepare SQL query. It should still be validated even if Exec or Query is not executed on that prepared statement.
  • 2016-02-23 - added sqlmock.AnyArg() function to provide any kind of argument matcher.
  • 2016-02-23 - convert expected arguments to driver.Value as natural driver does, the change may affect time.Time comparison and will be stricter. See issue.
  • 2015-08-27 - v1 api change, concurrency support, all known issues fixed.
  • 2014-08-16 instead of panic during reflect type mismatch when comparing query arguments - now return error
  • 2014-08-14 added sqlmock.NewErrorResult which gives an option to return driver.Result with errors for interface methods, see issue
  • 2014-05-29 allow to match arguments in more sophisticated ways, by providing an sqlmock.Argument interface
  • 2014-04-21 introduce sqlmock.New() to open a mock database connection for tests. This method calls sql.DB.Ping to ensure that connection is open, see issue. This way on Close it will surely assert if all expectations are met, even if database was not triggered at all. The old way is still available, but it is advisable to call db.Ping manually before asserting with db.Close.
  • 2014-02-14 RowsFromCSVString is now a part of Rows interface named as FromCSVString. It has changed to allow more ways to construct rows and to easily extend this API in future. See issue 1 RowsFromCSVString is deprecated and will be removed in future

Contributions

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

License

The three clause BSD license

Issues
  • introduce MockConn type, which represents isolated connections

    introduce MockConn type, which represents isolated connections

    Hi, this is an attempt to isolate connections for parallel testing. Coincidentally I had to solve this issue for myself as well.

    Since the sql.Open() does a whole lot more than just passing a driver.Conn I had to identify instances using IDs and passing them in the DSN.

    Should help with #9

    opened by wongak 18
  • INSERT while mocking gorm

    INSERT while mocking gorm

    I'm having a lot of trouble mocking gorm INSERT queries. I was able to get my tests passing when selecting fine, but I am running into this error when inserting.

    # Gorm's debug output
    INSERT INTO "groups" ("created_at","updated_at","deleted_at","name","description") VALUES ('2018-05-01 17:46:15','2018-05-01 17:46:15',NULL,'Group 1','A good group') RETURNING "groups"."id"
    
    # Error returned from *gorm.DB.Create
    2018/05/01 17:46:15 Error creating group: call to Query 'INSERT INTO "groups" ("created_at","updated_at","deleted_at","name","description") VALUES ($1,$2,$3,$4,$5) RETURNING "groups"."id"' with args [{Name: Ordinal:1 Value:2018-05-01 17:46:15.384319544 -0700 PDT m=+0.005382104} {Name: Ordinal:2 Value:2018-05-01 17:46:15.384319544 -0700 PDT m=+0.005382104} {Name: Ordinal:3 Value:<nil>} {Name: Ordinal:4 Value:Group 1} {Name: Ordinal:5 Value:A good group}], was not expected, next expectation is: ExpectedExec => expecting Exec or ExecContext which:
      - matches sql: '^INSERT INTO "groups" (.+)$'
      - is with arguments:
        0 - {}
        1 - {}
        2 - <nil>
        3 - Group 1
        4 - A good group
      - should return Result having:
          LastInsertId: 1
          RowsAffected: 1
    

    I have tried multiple different versions of the regex, even tested the match using golang on regex101.com, but I can't seem to get my sqlmock to match gorm's insert.

    Here is my test:

    type AnyTime struct{} // I don't actually know if I even need this
    
    func (a AnyTime) Match(v driver.Value) bool {
    	_, ok := v.(time.Time)
    	return ok
    }
    
    func TestGroupService_Create(t *testing.T) {
    	db, mock, err := sqlmock.New()
    	if err != nil {
    		log.Fatalf("can't create sqlmock: %s", err)
    	}
    	models.DB, err = gorm.Open("postgres", db)
    	if err != nil {
    		log.Fatalf("can't open gorm connection: %s", err)
    	}
    	defer db.Close()
    
    	models.DB.LogMode(true)
    
    	name := "Group 1"
    	description := "A good group"
    
    	mock.ExpectExec("^INSERT INTO \"groups\" (.+)$").WithArgs(AnyTime{}, AnyTime{}, nil, name, description).WillReturnResult(sqlmock.NewResult(1, 1))
    
    	s := GroupService{}
    
    	req := &pb.CreateGroupRequest{
    		Name: name,
    		Description: description,
    	}
    
    	resp, err := s.Create(context.Background(), req)
    	assert.Nil(t, err)
    
    	if assert.NotNil(t, resp) {
    		assert.Equal(t, resp.Group.Name, name)
    		assert.Equal(t, resp.Group.Description, description)
    	}
    
    	err = mock.ExpectationsWereMet()
    	assert.Nil(t, err)
    }
    

    and my service method I'm trying to test:

    func (server *GroupService) Create(ctx context.Context, request *pb.CreateGroupRequest) (*pb.CreateGroupReply, error) {
    	var group models.Group
    
    	group.Name = request.Name
    	group.Description = request.Description
    
    	db := models.DB
    
    	if err := db.Create(&group).Error; err != nil {
    		log.Printf("Error creating group: %v", err)
    		return nil, err
    	}
    
    	createReply := pb.CreateGroupReply{
    		Group: mapGroupToService(group),
    	}
    
    	return &createReply, nil
    }
    

    I just can't seem to figure this out. Thanks!

    opened by tfmertz 15
  • No known way to fail on unexpected calls

    No known way to fail on unexpected calls

    I want to make sure the query executed when an expectation is not met is not executed. I looked but there does not seem to be any option to do a sqlMock.ExpectExec().Times(0) or a slMock.FailOnUnexpectedMatches(true) or sqlMock.FailOnExec(). Please let me know/ show me an example on how to work around this. We cannot test an important condition without it

    opened by nazneen84 13
  • Rows does not implement database/sql/driver.Rows

    Rows does not implement database/sql/driver.Rows

    The new Rows struct is not backward compatible with the previous Rows interface; it's missing all of the driver.Rows methods. T

    he changelog and commit message from #68 leads one to believe that was an inadvertent change.

    opened by bhcleek 12
  • v1.3.1 Breaks build

    v1.3.1 Breaks build

    Any idea what is going on here? This has been happening for us since the 1.3.1 release.

    go: finding gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.1
    go: gopkg.in/DATA-DOG/[email protected]: go.mod has non-....v1 module path "sqlmock" at revision v1.3.1
    
    opened by KillerX 12
  • Expectations are not met

    Expectations are not met

    Hi,

    i am mocking a insert statement but the expectation fails, event though i cannot see why. The following error message reveal that the arguments are identical.

    sql_writer_test.go:29: error was not expected while writing event: exec query 'INSERT INTO Event (SourceId, Created, EventType, Version, Payload) VALUES (?, ?, ?, ?, ?)', args [2eb5880e-4bfd-4450-92fc-df851bae5dbb 2016-02-03 22:05:00.712109 +0000 UTC TEST 1 {"version":1,"name":"Joe","balance":12.99,"birth_date":"2015-12-13T23:59:59+02:00"}] does not match expected [2eb5880e-4bfd-4450-92fc-df851bae5dbb 2016-02-03 22:05:00.712109 +0000 UTC TEST 1 {"version":1,"name":"Joe","balance":12.99,"birth_date":"2015-12-13T23:59:59+02:00"}]

    Am i doing something wrong?

    enhancement 
    opened by mantzas 11
  • concurrency support, closes #20 and closes #9 and closes #15

    concurrency support, closes #20 and closes #9 and closes #15

    After some use cases and

    Refactor to support concurrency and multiple connections per mock database instance. When this branch will be merged, there will be BC break and a new major version bump.

    Solves the following issues:

    • [x] parallel tests, any number of mock databases, closes #9 extends and closes #10
    • [x] since rows holds a connection reserved, allow to open any number of connections, closes #20
    • [x] allow to expect database close to be called, closes #15
    • [x] more expectations, for example allow for rows to return error at any point. closes #13
    • [x] deprecated methods: RowsFromCSVString will be removed
    • [x] allow unordered expectation matching, support for goroutines, see test.
    • [x] all possible places where values may be changed, should be available for mocking.
    • [x] more expressive errors
    • [x] documentation updated
    • [x] allow null values from csv string to be converted to nil. closes #22
    opened by l3pp4rd 10
  • latest go-sqlmock(v1.3.3) and gorm(v1.9.11) version incompatible

    latest go-sqlmock(v1.3.3) and gorm(v1.9.11) version incompatible

    Use gorm-ut source with upgrade deps version, go.mod:

    module github.com/Rosaniline/gorm-ut
    
    go 1.13
    
    require (
    	github.com/DATA-DOG/go-sqlmock v1.3.3
    	github.com/go-test/deep v1.0.4
    	github.com/jinzhu/gorm v1.9.11
    	github.com/satori/go.uuid v1.2.0
    	github.com/stretchr/testify v1.4.0
    )
    

    and run test, command line shows:

    ?[35m(C:/Users/ping/Desktop/gorm-ut-master/pkg/repository/person.go:24)?[0m
    ?[33m[2019-10-21 15:52:57]?[0m ?[31;1m call to database transaction Begin, was not expected, next expectation is: ExpectedQuery => expecting Query, QueryContext or QueryRow which:
      - matches sql: 'INSERT INTO "person" \("id","name"\)
                            VALUES \(\$1,\$2\) RETURNING "person"\."id"'
      - is with arguments:
        0 - c34a302e-bc5d-4e3d-8104-680ca2a438bb
        1 - test-name
      - should return rows:
        row 0 - [c34a302e-bc5d-4e3d-8104-680ca2a438bb] ?[0m
    
    ?[35m(C:/Users/ping/Desktop/gorm-ut-master/pkg/repository/person.go:30)?[0m
    ?[33m[2019-10-21 15:52:57]?[0m ?[31;1m Query: could not match actual sql: "SELECT * FROM "person" WHERE (id = ?)" with expected regexp "INSERT INTO "person" \("id","name"\) VALUES \(\$
    1,\$2\) RETURNING "person"\."id"" ?[0m
    
    ?[35m(C:/Users/ping/Desktop/gorm-ut-master/pkg/repository/person.go:30)?[0m
    ?[33m[2019-10-21 15:52:57]?[0m  ?[36;1m[0.00ms]?[0m  SELECT * FROM "person"  WHERE (id = 'd5328d68-8664-4aab-ad92-8b74e3010ea8')
    ?[36;31m[0 rows affected or returned ]?[0m
    --- FAIL: TestInit (0.01s)
        --- FAIL: TestInit/Test_repository_Create (0.01s)
            person_test.go:85:
                    Error Trace:    person_test.go:85
                    Error:          Received unexpected error:
                                    call to database transaction Begin, was not expected, next expectation is: ExpectedQuery => expecting Query, QueryContext or QueryRow which:
                                      - matches sql: 'INSERT INTO "person" \("id","name"\)
                                                            VALUES \(\$1,\$2\) RETURNING "person"\."id"'
                                      - is with arguments:
                                        0 - c34a302e-bc5d-4e3d-8104-680ca2a438bb
                                        1 - test-name
                                      - should return rows:
                                        row 0 - [c34a302e-bc5d-4e3d-8104-680ca2a438bb]
                    Test:           TestInit/Test_repository_Create
            person_test.go:45:
                    Error Trace:    person_test.go:45
                                                            suite.go:126
                                                            panic.go:563
                                                            testing.go:653
                                                            person_test.go:85
                    Error:          Received unexpected error:
                                    there is a remaining expectation which was not matched: ExpectedQuery => expecting Query, QueryContext or QueryRow which:
                                      - matches sql: 'INSERT INTO "person" \("id","name"\)
                                                            VALUES \(\$1,\$2\) RETURNING "person"\."id"'
                                      - is with arguments:
                                        0 - c34a302e-bc5d-4e3d-8104-680ca2a438bb
                                        1 - test-name
                                      - should return rows:
                                        row 0 - [c34a302e-bc5d-4e3d-8104-680ca2a438bb]
                    Test:           TestInit/Test_repository_Create
        --- FAIL: TestInit/Test_repository_Get (0.00s)
            person_test.go:66:
                    Error Trace:    person_test.go:66
                    Error:          Received unexpected error:
                                    Query: could not match actual sql: "SELECT * FROM "person" WHERE (id = ?)" with expected regexp "INSERT INTO "person" \("id","name"\) VALUES \(\$1,\$2\)
     RETURNING "person"\."id""
                    Test:           TestInit/Test_repository_Get
            person_test.go:45:
                    Error Trace:    person_test.go:45
                                                            suite.go:126
                                                            panic.go:563
                                                            testing.go:653
                                                            person_test.go:66
                    Error:          Received unexpected error:
                                    there is a remaining expectation which was not matched: ExpectedQuery => expecting Query, QueryContext or QueryRow which:
                                      - matches sql: 'INSERT INTO "person" \("id","name"\)
                                                            VALUES \(\$1,\$2\) RETURNING "person"\."id"'
                                      - is with arguments:
                                        0 - c34a302e-bc5d-4e3d-8104-680ca2a438bb
                                        1 - test-name
                                      - should return rows:
                                        row 0 - [c34a302e-bc5d-4e3d-8104-680ca2a438bb]
                    Test:           TestInit/Test_repository_Get
    FAIL
    FAIL    github.com/Rosaniline/gorm-ut/pkg/repository    0.345s
    FAIL
    

    If not upgrade deps, keep it with origin repo, it works.

    opened by navono 10
  • ExpectPrepare (and likely Expect*) fail when using `?` as parameter token not at end of query

    ExpectPrepare (and likely Expect*) fail when using `?` as parameter token not at end of query

    When declaring ExpectPrepare for a query with a ? not at the end of the query, the test will fail, stating that the regex does not match.

    Test code:

    func TestPrepare() {
        sampleQuery := "SELECT * FROM accounts WHERE source = ? LIMIT 100"
        db, mock, err := sqlmock.New()
        mock.ExpectPrepare(sampleQuery)
        db.Prepare(sampleQuery)
    }
    

    Error:

    query 'SELECT * FROM accounts WHERE source = ? LIMIT 100', does not match regex [SELECT * FROM accounts WHERE source = ? LIMIT 100]
    

    This is, of course, due to the question mark in the sql, but that should be detected when creating the expectation.

    By contrast, the following will succeed:

    func TestPrepare() {
        sampleQuery := "SELECT * FROM accounts WHERE source = ?"
        db, mock, err := sqlmock.New()
        mock.ExpectPrepare(sampleQuery)
        db.Prepare(sampleQuery)
    }
    
    enhancement 
    opened by XerxesDGreat 8
  • feature request: allow to set mocks on transactions

    feature request: allow to set mocks on transactions

    my code calls internally to tx.Stmt() which returns a new statement but there's no way (or at least I can't find it) to set expectation on it.

    opened by dcu 8
  • Feed a mocked database with a SQL dump file

    Feed a mocked database with a SQL dump file

    Is it possible to feed a mocked database with a SQL dump file to generate the desired schema?

    opened by droslean 0
  • Really confused about the default sql matcher

    Really confused about the default sql matcher

    By default, sqlmock is preserving backward compatibility and default query matcher is sqlmock.QueryMatcherRegexp which uses expected SQL string as a regular expression to match incoming query string. However, I always encountered could not match actual sql: exception:

    My repository code:

    	accountID := "a1"
    	baseTime := "2023-04-17T00:00:00Z"
    	offset := 0
    	pageSize := 10
    	c.mockedDB.Mock.
    		ExpectQuery(regexp.QuoteMeta(`SELECT yaye_events.* FROM yaye_events left join event_pinnings on yaye_events.id = event_pinnings.event_id.event_id WHERE event_pinnings.account_id != ? AND ((? >= yaye_events.start_date and ? <= yaye_events.end_date) OR ? > yaye_events.end_date) ORDER BY yaye_events.start_date desc LIMIT ?`)).
    		WithArgs(accountID, baseTime, baseTime, baseTime, pageSize+1).
    		WillReturnRows(&sqlmock.Rows{})
    

    My test code:

    c.mockedDB.Mock.
    		ExpectQuery(regexp.QuoteMeta(`SELECT yaye_events(.*) FROM yaye_events left join event_pinnings on yaye_events.id = event_pinnings.event_id.event_id WHERE event_pinnings.account_id != (.+) AND (((.+) >= yaye_events.start_date and (.+) <= yaye_events.end_date) OR (.+) > yaye_events.end_date) ORDER BY yaye_events.start_date desc LIMIT 11`)).
    		WithArgs(accountID, baseTime, baseTime, baseTime, pageSize+1).
    		WillReturnRows(&sqlmock.Rows{})
    

    No matter how I changed the query string, I always encountered the following exception:

    could not match actual sql: "SELECT yaye_events.* FROM `yaye_events` left join event_pinnings on yaye_events.id = event_pinnings.event_id.event_id WHERE event_pinnings.account_id != ? AND ((? >= yaye_events.start_date and ? <= yaye_events.end_date) OR ? > yaye_events.end_date) ORDER BY yaye_events.start_date desc LIMIT 11" with expected regexp "SELECT yaye_events\(\.\*\) FROM yaye_events left join event_pinnings on yaye_events\.id = event_pinnings\.event_id\.event_id WHERE event_pinnings\.account_id != \(\.\+\) AND \(\(\(\.\+\) >= yaye_events\.start_date and \(\.\+\) <= yaye_events\.end_date\) OR \(\.\+\) > yaye_events\.end_date\) ORDER BY yaye_events\.start_date desc LIMIT 11"; Query: could not match actual sql: "SELECT yaye_events.* FROM `yaye_events` left join event_pinnings on yaye_events.id = event_pinnings.event_id.event_id WHERE event_pinnings.account_id != ? AND ((? >= yaye_events.start_date and ? <= yaye_events.end_date) OR ? > yaye_events.end_date) ORDER BY yaye_events.start_date desc LIMIT 11" with expected regexp "SELECT yaye_events\(\.\*\) FROM yaye_events left join event_pinnings on yaye_events\.id = event_pinnings\.event_id\.event_id WHERE event_pinnings\.account_id != \(\.\+\) AND \(\(\(\.\+\) >= yaye_events\.start_date and \(\.\+\) <= yaye_events\.end_date\) OR \(\.\+\) > yaye_events\.end_date\) ORDER BY yaye_events\.start_date desc LIMIT 11"
    

    I really confused about how should I write my test code to match the actual query.

    opened by rantianhua 2
  • Operations on go-sqlmock.Driver fail with: expected a connection to be available, but it is not

    Operations on go-sqlmock.Driver fail with: expected a connection to be available, but it is not

    Hello,

    I'm working on a package that wraps an sql.Driver and adds functionality. To test it, I'm trying to use go-sqlmock. I'm running into the issue that if I wrap the go-sqlmock Driver, all operations fail with the error: expected a connection to be available, but it is not

    I'm accessing the driver via:

    db, _, _ := sqlmock.New()
    db.Driver()
    

    This can be reproduced e.g. via sqlmw:

    package dddbmock_test
    
    import (
    	"database/sql"
    	"testing"
    
    	"github.com/DATA-DOG/go-sqlmock"
    	"github.com/ngrok/sqlmw"
    )
    
    func TestMWWrap(t *testing.T) {
    	db, _, err := sqlmock.New()
    	if err != nil {
    		t.Fatal("sqlmock new failed:", err)
    	}
    
    	sql.Register(
    		"mwdriver",
    		sqlmw.Driver(db.Driver(), &sqlmw.NullInterceptor{}),
    	)
    
    	db, err = sql.Open("mydriver", "")
    	if err != nil {
    		t.Fatal("opening driver failed:", err)
    	}
    
    	if err := db.Ping(); err != nil {
    		t.Error("ping failed", err)
    	}
    }
    

    Without using other external packages and mimicking the wrapping behavior instead it can be reproduced like:

    package dddbmock_test
    
    import (
    	"database/sql"
    	"testing"
    
    	"github.com/DATA-DOG/go-sqlmock"
    )
    
    func TestRegister(t *testing.T) {
    	db, _, err := sqlmock.New(sqlmock.MonitorPingsOption(true))
    	if err != nil {
    		t.Fatal("sqlmock new failed:", err)
    	}
    
    	sql.Register("mydriver", db.Driver())
    
    	db, err = sql.Open("mydriver", "")
    	if err != nil {
    		t.Fatal("opening driver failed:", err)
    	}
    
    	if err := db.Ping(); err != nil {
    		t.Error("ping failed", err)
    	}
    
    	if _, err := db.Exec(""); err != nil {
    		t.Error("exec failed", err)
    	}
    }
    

    The comment https://github.com/DATA-DOG/go-sqlmock/issues/83#issuecomment-582962456 seems to be about the same issue. I guess it's not intended to be used like that, but it would be awesome to support operations on the go-sqlmock Driver.

    opened by fho 2
  • String

    String

    Is there any way compare any string like anytime in go-sqlmock

    opened by afzalabbasi 0
  • Arguments Error

    Arguments Error

    hey All mock.ExpectExec("SELECT * FROM permission WHERE roleid = $1").WithArgs(2) this is my mock queey i just compare that one with the original query which one is db.Get(&programinfo, "SELECT * FROM permission WHERE roleid = $1", roleid) but i found that error call to Query 'SELECT * FROM permission WHERE roleid = $1' with args [{Name: Ordinal:1 Value:2}], was not expected, next expectation is: ExpectedExec => expecting Exec or ExecContext which:

    • matches sql: 'SELECT * FROM permission WHERE roleid = $1'
    • is with arguments: there is a remaining expectation which was not matched: ExpectedExec => expecting Exec or ExecContext which: - matches sql: 'SELECT * FROM permission WHERE roleid = $1' - is with arguments: 0 - 2 Can SomeOne please help me how i fixed this issue Thanks
    opened by afzalabbasi 0
  • Add Multi Row Support

    Add Multi Row Support

    Closes #135

    This PR adds the AddRows function to the API which will allow users to add multiple rows at once instead of calling AddRow multiple times.

    opened by asahasrabuddhe 2
  • Mock time.Now()

    Mock time.Now()

    I have a function with

    func (r *repository) Update(ctx context.Context, book *models.Book) error {
    	now := time.Now()
    
    	_, err := r.db.ExecContext(ctx, UPDATE books set title = $1, description = $2, published_date = $3, image_url = $4, updated_at = $5 where book_id = $6, book.Title, book.Description,
    		book.PublishedDate, book.ImageURL, now, book.BookID)
    	if err != nil {
    		return err
    	}
    
    	return nil
    }
    

    that I tried to unit test with

    func TestRepository_Update(t *testing.T) {
    	db, mock := NewMock()
    	repo := New(db)
    
    	mockBook := &models.Book{
    		BookID:        1,
    		Title:         "test1",
    		PublishedDate: timeWant(),
    		ImageURL: null.String{
    			String: "https://example.com/image.png",
    			Valid:  true,
    		},
    		Description: "test1",
    	}
    
    	mock.ExpectExec("UPDATE books set title").
    		WithArgs(mockBook.Title, mockBook.Description, mockBook.PublishedDate, mockBook.ImageURL.String, time.Now().String(), mockBook.BookID).
    		WillReturnResult(sqlmock.NewErrorResult(nil))
    
    	err := repo.Update(context.Background(), mockBook)
    
    	assert.NoError(t, err)
    }
    

    The fails obviously because the value of time.Now() in the test and in the implementation are different.

    === RUN   TestRepository_Update
        postgres_test.go:189: 
            	Error Trace:	postgres_test.go:189
            	Error:      	Received unexpected error:
            	            	ExecQuery 'UPDATE books set title = $1, description = $2, published_date = $3, image_url = $4, updated_at = $5 where book_id = $6', arguments do not match: argument 4 expected [string - 2021-05-26 22:07:58.847659183 +1000 AEST m=+0.001800825] does not match actual [time.Time - 2021-05-26 22:07:58.847710743 +1000 AEST m=+0.001852395]
            	Test:       	TestRepository_Update
    --- FAIL: TestRepository_Update (0.00s)
    

    How do you write unit a test when the implementation has a value that will change like time.Now() or somehow mock time.Now()

    For reference, book struct

    type Book struct {
    	BookID        int64       `db:"book_id" json:"book_id"`
    	Title         string      `db:"title" json:"title"`
    	PublishedDate time.Time   `db:"published_date" json:"published_date"`
    	ImageURL      null.String `db:"image_url" json:"image_url,`
    	Description   string      `db:"description" json:"description"`
    	CreatedAt     null.Time   `db:"created_at" json:"created_at,`
    	UpdatedAt     null.Time   `db:"updated_at" json:"updated_at,`
    	DeletedAt     null.Time   `db:"deleted_at" json:"deleted_at,`
    }
    
    opened by gmhafiz 2
  • First commit

    First commit

    opened by dungbond007 1
  • first commit in test file

    first commit in test file

    just a test file

    opened by balajibala123 0
  • Options for non-strict mock - allow unexpected calls

    Options for non-strict mock - allow unexpected calls

    While strict mock is very valuable, it's also very restrictive in how we can use this library. strict mocks force all expectation to be met, and also that anything that happens on the mock was expected.

    This makes tests break for unrelated changes, and encourages tests that verify a lot of behaviors in a single test. for me, testing that a transaction gets commited in a specific case, is a different test than testing what query was sent.

    It would be nice if we could add an option to sqlmock.New() that relaxes the expectations.

    sqlmock.New(sqlmock.AllowUnexpectedCalls()) // or something similar
    

    I would like to only fail the test if the expectation that I have defined are not met, but ignore calls that were not expected.

    opened by serbrech 4
Releases(v1.5.0)
Owner
DATA-DOG
Happy awesome developers
DATA-DOG
Completely type-safe compile-time mock generator for Go

Mockc Mockc is a completely type-safe compile-time mock generator for Go. You can use it just by writing the mock generators with mockc.Implement() or

Geon Kim 29 May 23, 2021
A library to aid unittesting code that uses Golang's Github SDK

go-github-mock A library to aid unittesting code that uses Golang's Github SDK Installation go get github.com/migueleliasweb/go-github-mock Features C

Miguel Elias dos Santos 5 Aug 27, 2021
manage your mocks / run mockgen more quickly / mocks up-to-date checking

gomockhandler If you find any bugs or have feature requests, please feel free to create an issue. gomockhandler is handler of golang/mock, as the name

Kensei Nakada 35 Sep 18, 2021
Full-featured test framework for Go! Assertions, mocking, input testing, output capturing, and much more! 🍕

testza ?? Testza is like pizza for Go - you could life without it, but why should you? Get The Module | Documentation | Contributing | Code of Conduct

Marvin Wendt 273 Sep 16, 2021
mockery - A mock code autogenerator for Golang

mockery - A mock code autogenerator for Golang

Vektra 2.9k Sep 21, 2021
Ruby on Rails like test fixtures for Go. Write tests against a real database

testfixtures Warning: this package will wipe the database data before loading the fixtures! It is supposed to be used on a test database. Please, doub

null 703 Sep 23, 2021
GoMock is a mocking framework for the Go programming language.

gomock GoMock is a mocking framework for the Go programming language. It integrates well with Go's built-in testing package, but can be used in other

Go 6.2k Sep 23, 2021
Powerful mock generation tool for Go programming language

Summary Minimock generates mocks out of Go interface declarations. The main features of minimock are: It generates statically typed mocks and helpers.

Juno Inc. 414 Sep 21, 2021
A toolkit with common assertions and mocks that plays nicely with the standard library

Testify - Thou Shalt Write Tests ℹ️ We are working on testify v2 and would love to hear what you'd like to see in it, have your say here: https://cutt

Stretchr, Inc. 14.4k Sep 24, 2021
Vitaly Berg 7 Aug 10, 2021
Immutable transaction isolated sql driver for golang

Single transaction based sql.Driver for GO Package txdb is a single transaction based database sql driver. When the connection is opened, it starts a

DATA-DOG 384 Sep 15, 2021
Lightweight HTTP mocking in Go (aka golang)

httpmock This library builds on Go's built-in httptest library, adding a more mockable interface that can be used easily with other mocking tools like

null 73 Jul 19, 2021
HTTP traffic mocking and testing made easy in Go ༼ʘ̚ل͜ʘ̚༽

gock Versatile HTTP mocking made easy in Go that works with any net/http based stdlib implementation. Heavily inspired by nock. There is also its Pyth

Tom 1.5k Sep 23, 2021
Record and replay your HTTP interactions for fast, deterministic and accurate tests

go-vcr go-vcr simplifies testing by recording your HTTP interactions and replaying them in future runs in order to provide fast, deterministic and acc

Marin Atanasov Nikolov 775 Sep 23, 2021
Datastore Testibility

Datastore Testibility (dsunit) This library is compatible with Go 1.10+ Please refer to CHANGELOG.md if you encounter breaking changes. Introduction M

Viant, Inc 38 Feb 14, 2021
End to end functional test and automation framework

Declarative end to end functional testing (endly) This library is compatible with Go 1.12+ Please refer to CHANGELOG.md if you encounter breaking chan

Viant, Inc 193 Sep 6, 2021
Cucumber for golang

Godog The API is likely to change a few times before we reach 1.0.0 Please read the full README, you may find it very useful. And do not forget to pee

Cucumber 1.5k Sep 25, 2021
Cucumber for golang

Godog The API is likely to change a few times before we reach 1.0.0 Please read the full README, you may find it very useful. And do not forget to pee

Cucumber 1.5k Sep 21, 2021
A Go implementation of Servirtium, a library that helps test interactions with APIs.

Servirtium is a server that serves as a man-in-the-middle: it processes incoming requests, forwards them to a destination API and writes the response into a Markdown file with a special format that is common across all of the implementations of the library.

Servirtium 5 Jan 27, 2021