go-sqlmock

repository·master·Indexed 27 days ago

https://github.com/data-dog/go-sqlmock

A mock library for the Go sql/driver interface that allows developers to simulate SQL driver behavior in tests without a real database connection. It provides tools to define expectations for queries, executions, transactions, and pings, and supports custom SQL query matching via the QueryMatcher interface and custom argument matching through the Argument interface.

Tokens
4.7K
Snippets
8
Records
47
Agent score
91%

What's inside go-sqlmock

  1. Use sqlmock for database testing

    master

    You can use sqlmock.New() to create a mock database connection (*sql.DB) and a mock object (sqlmock.Sqlmock) to define expectations. This allows you to simulate database behavior without a real connection.

    Common workflow:

    1. Call sqlmock.New() to get the db and mock objects.
    2. Define expectations on the mock object (e.g., ExpectBegin, ExpectExec, ExpectCommit).
    3. Execute your application code using the db object.
    4. Call mock.ExpectationsWereMet() to verify all expectations were fulfilled.
    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)
    	}
    }
  2. Match complex arguments using the Argument interface

    master

    For arguments that cannot be easily compared by value (like time.Time), you can implement the sqlmock.Argument interface. This allows you to define custom matching logic via a Match(v driver.Value) bool method.

    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) {
    	db, mock, err := sqlmock.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(sqlmock.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)
    	}
    }
  3. Customize SQL query matching

    master

    By default, sqlmock uses sqlmock.QueryMatcherRegexp, which treats the expected SQL string as a regular expression. You can customize this behavior using sqlmock.QueryMatcherOption when calling sqlmock.New or sqlmock.NewWithDSN.

    Available matchers:

    • sqlmock.QueryMatcherRegexp: (Default) Uses regular expressions.
    • sqlmock.QueryMatcherEqual: Performs a full case-sensitive equality match.
    db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
  4. Customize SQL query matching with QueryMatcherOption

    master
    Use QueryMatcherOption to replace the default QueryMatcherRegexp with a custom QueryMatcher. This allows you to define more sophisticated rules for how SQL query strings are matched against expectations.
  5. Use the SqlmockCommon interface to create expectations

    master
    The SqlmockCommon interface is the primary way to define expectations for database actions in your tests. You use these methods to queue expected SQL queries, transactions, and connection behaviors. Once your test code runs, you should call ExpectationsWereMet() to verify that all queued expectations were satisfied in the correct order (unless order matching is disabled).
  6. Populate mocked rows from a CSV string

    master
    Use FromCSVString to quickly build rows from a raw CSV string. The parser trims whitespace from columns and converts the string "null" (case-insensitive) to a nil value. The number of columns in each CSV line must match the columns defined in NewRows.
  7. Mock prepared statements with ExpectPrepare

    master
    Use ExpectPrepare(expectedSQL string) to expect a call to Prepare(). This returns an *ExpectedPrepare object, which allows you to further mock responses on the resulting statement, such as subsequent Query() or Exec() calls.
  8. Configure expectation matching order

    master
    By default, sqlmock expects all database actions to occur in the exact order they were defined. If your code uses goroutines to execute queries in parallel, you can use MatchExpectationsInOrder(false) to allow expectations to be matched in any order.
  9. Mock transactions with ExpectBegin, ExpectCommit, and ExpectRollback

    master

    To test transaction logic, queue expectations for the lifecycle of a transaction:

    • ExpectBegin(): Expects *sql.DB.Begin to be called.
    • ExpectCommit(): Expects *sql.Tx.Commit to be called.
    • ExpectRollback(): Expects *sql.Tx.Rollback to be called.