go_mocket

package module
v1.0.16 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 6, 2022 License: MIT Imports: 13 Imported by: 0

README

GoDoc Build Status Go Report Card

Go-Mocket

Go-Mocket is library inspired by DATA-DOG/go-sqlmock As inspiration library it is implementation of sql/driver interface but at the same time follows different approaches and has only similar API. This library helps to mock any DB connection also with jinzhu/gorm and it was main goal to create it

List of features in the library:

  • Mock INSERT, UPDATE, SELECT, DELETE
  • Support of transactions
  • 2 API's to use - chaining and via specifying whole mock object
  • Matching by prepared statements arguments
  • You will not require to change anything inside you code to start using this library
  • Ability to trigger exceptions
  • Attach callbacks to mocked response to add additional check or modify response

NOTE Please be aware that driver catches SQL without DB specifics. Generating of queries is done by sql package

Install

go get github.com/Selvatico/go-mocket

Usage

There are two possible ways to use mocket:

  • Chaining API
  • Specifying FakeResponse object with all fields manually. Could be useful for cases when mocks stored separately as list of FakeResponses.
Enabling driver

Somewhere in you code to setup a tests

import (
    "database/sql"
    mocket "github.com/Selvatico/go-mocket"
    "github.com/jinzhu/gorm"
)

func SetupTests() {
    mocket.Catcher.Register()
    // GORM
    db, err := gorm.Open(mocket.DRIVER_NAME, "any_string") // Could be any connection string
    app.DB = db // assumption that it will be used everywhere the same
    //OR 
    // Regular sql package usage
    db, err := sql.Open(mocket.DRIVER_NAME, "any_string")
}

Now if use singleton instance of DB it will use everywhere mocked connection.

Chain usage
Example of mocking by pattern
import mocket "github.com/Selvatico/go-mocket"
import "net/http/httptest"

func TestHandler(t *testing.T) {
    request := httptest.NewRequest("POST", "/application", nil)
    recorder := httptest.NewRecorder()

    GlobalMock := mocket.Catcher
    GlobalMock.Logging = true // log mocket behavior

    commonReply := []map[string]interface{}{{"id": "2", "field": "value"}}
    // Mock only by query pattern
    GlobalMock.NewMock().WithQuery(`"campaigns".name IS NULL AND (("uuid" = test_uuid))`).WithReply(commonReply)
    Post(recorder, request) // call handler

    r := recorder.Result()
    body, _ := ioutil.ReadAll(r.Body)

    // some assertion about results
    //...
}

Documentation

For More Documentation please check Wiki Documentation

License

MIT License

Copyright (c) 2017 Seredenko Dmitry

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Documentation

Overview

Package go_mocket is way to mock DB for GORM and just sql package usage First you need to activate package somewhere in your tests code like this

	package main

	import (
    	"database/sql"
    	mocket "github.com/Selvatico/go-mocket"
    	"github.com/jinzhu/gorm"
	)

	var DB *gorm.DB

	func SetupTests() {
    	mocket.Catcher.Register()
    	// GORM
    	db, err := gorm.Open("fake_test", "connection_string") // Could be any connection string
    	DB = db

		// OR
    	// Regular sql package usage
    	db, err := sql.Open(driver, source)
	}

	func GetUsers(db *sql.DB) []map[string]interface {} {
		var res []map[string]interface{}
		age := 27
		rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
		if err != nil {
			log.Fatal(err)
		}
		defer rows.Close()
		for rows.Next() {
			var name string
			var age string
			if err := rows.Scan(&name, &age); err != nil {
				log.Fatal(err)
			}
			//fmt.Printf("%s is %d\n", name, age)
			row := make(map[string]interface{})
			row["name"] = name
			row["age"] = age
			res = append(res, row)
		}
		if err := rows.Err(); err != nil {
			log.Fatal(err)
		}
		return res
	}

Somewhere in you tests:

package main

import (
	"log"
	"testing"
	"database/sql"
	mocket "github.com/Selvatico/go-mocket"
)

func TestResponses (t *testing.T) {
	mocket.Catcher.Register()
	db, _ := sql.Open("fake_test", "connection_string") // Could be any connection string
	DB = db

	t.Run("Simple SELECT caught by query", func(t *testing.T) {
		mocket.Catcher.Logging = true
		commonReply := []map[string]interface{}{{"name": "FirstLast", "age": "30"}}
		mocket.Catcher.Reset().NewMock().WithQuery(`SELECT name FROM users WHERE`).WithReply(commonReply)
		result := GetUsers(DB)
		if len(result) != 1 {
			t.Errorf("Returned sets is not equal to 1. Received %d", len(result))
		}
		if result[0]["age"] != "30" {
			t.Errorf("Age is not equal. Got %v", result[0]["age"])
		}
	})
}

For more information and use cases please check: https://github.com/Selvatico/go-mocket

Index

Constants

View Source
const (
	DRIVER_NAME = "MOCK_FAKE_DRIVER"
)

Variables

View Source
var HookBadCommit func() bool

hook to simulate broken connections

View Source
var HookBadRollback func() bool

hook to simulate broken connections

Functions

func NewFakeResult

func NewFakeResult(insertId int64, rowsAffected int64) driver.Result

NewFakeResult returns result interface instance

Types

type Exceptions

type Exceptions struct {
	HookQueryBadConnection func() bool
	HookExecBadConnection  func() bool
}

Exceptions represents possible exceptions during query executions

type FakeConn

type FakeConn struct {
	// contains filtered or unexported fields
}

FakeConn implements connection

func (*FakeConn) Begin

func (c *FakeConn) Begin() (driver.Tx, error)

Begin starts and returns a new transaction.

func (*FakeConn) Close

func (c *FakeConn) Close() (err error)

func (*FakeConn) Exec

func (c *FakeConn) Exec(query string, args []driver.Value) (driver.Result, error)

Exec is deprecated

func (*FakeConn) ExecContext

func (c *FakeConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error)

ExecContext is optional to implement and it returns skip

func (*FakeConn) Prepare

func (c *FakeConn) Prepare(query string) (driver.Stmt, error)

Prepare is optional

func (*FakeConn) PrepareContext

func (c *FakeConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error)

PrepareContext returns a prepared statement, bound to this connection. context is for the preparation of the statement, it must not store the context within the statement itself.

func (*FakeConn) Query

func (c *FakeConn) Query(query string, args []driver.Value) (driver.Rows, error)

Query is deprecated

func (*FakeConn) QueryContext

func (c *FakeConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error)

QueryContext is optional

type FakeDB

type FakeDB struct {
	// contains filtered or unexported fields
}

type FakeDriver

type FakeDriver struct {
	// contains filtered or unexported fields
}

FakeDriver implements driver interface in sql package

func (FakeDriver) Open

func (d FakeDriver) Open(database string) (driver.Conn, error)

Open returns a new connection to the database.

type FakeResponse

type FakeResponse struct {
	Pattern      string                            // SQL query pattern to match with
	Args         []interface{}                     // List args to be matched with
	Response     []map[string]interface{}          // Array of rows to be parsed as result
	Once         bool                              // To trigger only once
	Triggered    bool                              // If it was triggered at least once
	Callback     func(string, []driver.NamedValue) // Callback to execute when response triggered
	RowsAffected int64                             // Defines affected rows count
	LastInsertId int64                             // ID to be returned for INSERT queries
	Error        error                             // Any type of error which could happen dur

	*Exceptions
	// contains filtered or unexported fields
}

FakeResponse represents mock of response with holding all required values to return mocked response

func (*FakeResponse) IsMatch

func (fr *FakeResponse) IsMatch(query string, args []driver.NamedValue) bool

IsMatch checks if both query and args matcher's return true and if this is Once mock

func (*FakeResponse) MarkAsTriggered

func (fr *FakeResponse) MarkAsTriggered()

MarkAsTriggered marks response as executed. For one time catches it will not make this possible to execute anymore

func (*FakeResponse) OneTime

func (fr *FakeResponse) OneTime() *FakeResponse

OneTime sets current mock to be triggered only once

func (*FakeResponse) WithArgs

func (fr *FakeResponse) WithArgs(vars ...interface{}) *FakeResponse

WithArgs attaches Args check for prepared statements

func (*FakeResponse) WithCallback

func (fr *FakeResponse) WithCallback(f func(string, []driver.NamedValue)) *FakeResponse

WithCallback adds callback to be executed during matching

func (*FakeResponse) WithError added in v1.0.3

func (fr *FakeResponse) WithError(err error) *FakeResponse

WithError sets Error to FakeResponse struct to have it available on any statements executed example: WithError(sql.ErrNoRows)

func (*FakeResponse) WithExecException

func (fr *FakeResponse) WithExecException() *FakeResponse

WithExecException says that if mock attached to non-SELECT query we need to trigger error there

func (*FakeResponse) WithId

func (fr *FakeResponse) WithId(id int64) *FakeResponse

WithId sets ID to be considered as insert ID for INSERT statements

func (*FakeResponse) WithQuery

func (fr *FakeResponse) WithQuery(query string) *FakeResponse

WithQuery adds SQL query pattern to match for

func (*FakeResponse) WithQueryException

func (fr *FakeResponse) WithQueryException() *FakeResponse

WithQueryException adds to SELECT mocks triggering of error

func (*FakeResponse) WithReply

func (fr *FakeResponse) WithReply(response []map[string]interface{}) *FakeResponse

WithReply adds to chain and assign some parts of response

func (*FakeResponse) WithRowsNum

func (fr *FakeResponse) WithRowsNum(num int64) *FakeResponse

WithRowsNum specifies how many records to consider as affected

type FakeResult

type FakeResult struct {
	// contains filtered or unexported fields
}

FakeResult implementation of sql Result interface

func (*FakeResult) LastInsertId

func (fr *FakeResult) LastInsertId() (int64, error)

LastInsertId required to give sql package ability get ID of inserted record

func (*FakeResult) RowsAffected

func (fr *FakeResult) RowsAffected() (int64, error)

RowsAffected returns the number of rows affected

type FakeStmt

type FakeStmt struct {
	// contains filtered or unexported fields
}

FakeStmt is implementation of Stmt sql interfcae

func (*FakeStmt) Close

func (s *FakeStmt) Close() error

func (*FakeStmt) ColumnConverter

func (s *FakeStmt) ColumnConverter(idx int) driver.ValueConverter

ColumnConverter returns a ValueConverter for the provided column index.

func (*FakeStmt) Exec deprecated

func (smt *FakeStmt) Exec(args []driver.Value) (driver.Result, error)

Exec executes a query that doesn't return rows, such as an INSERT or UPDATE.

Deprecated: Drivers should implement StmtExecContext instead (or additionally).

func (*FakeStmt) ExecContext

func (smt *FakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error)

ExecContext executes a query that doesn't return rows, such as an INSERT or UPDATE.

func (*FakeStmt) NumInput

func (s *FakeStmt) NumInput() int

NumInput returns the number of placeholder parameters.

func (*FakeStmt) Query deprecated

func (s *FakeStmt) Query(args []driver.Value) (driver.Rows, error)

Query executes a query that may return rows, such as a SELECT.

Deprecated: Drivers should implement StmtQueryContext instead (or additionally).

func (*FakeStmt) QueryContext

func (smt *FakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error)

QueryContext executes a query that may return rows, such as a SELECT.

type FakeTx

type FakeTx struct {
	// contains filtered or unexported fields
}

FakeTx implements Tx interface

func (*FakeTx) Commit

func (tx *FakeTx) Commit() error

func (*FakeTx) Rollback

func (tx *FakeTx) Rollback() error

type MockCatcher

type MockCatcher struct {
	Mocks                []*FakeResponse // Slice of all mocks
	Logging              bool            // Do we need to log what we catching?
	PanicOnEmptyResponse bool            // If not response matches - do we need to panic?
	// contains filtered or unexported fields
}

MockCatcher is global entity to save all mocks aka FakeResponses

var Catcher *MockCatcher

Catcher is global instance of Catcher used for attaching all mocks to connection

func (*MockCatcher) Attach

func (mc *MockCatcher) Attach(fr []*FakeResponse)

Attach several mocks to MockCather. Could be useful to attach mocks from some factories of mocks

func (*MockCatcher) FindResponse

func (mc *MockCatcher) FindResponse(query string, args []driver.NamedValue) *FakeResponse

FindResponse finds suitable response by provided

func (*MockCatcher) NewMock

func (mc *MockCatcher) NewMock() *FakeResponse

NewMock creates new FakeResponse and return for chains of attachments

func (*MockCatcher) Register added in v1.0.1

func (mc *MockCatcher) Register()

Register safely register FakeDriver

func (*MockCatcher) Reset

func (mc *MockCatcher) Reset() *MockCatcher

Reset removes all Mocks to start process again

func (*MockCatcher) SetLogging added in v1.0.14

func (mc *MockCatcher) SetLogging(l bool)

type RowsCursor

type RowsCursor struct {
	// contains filtered or unexported fields
}

RowsCursor is implementation of Rows sql interface

func (*RowsCursor) Close

func (rc *RowsCursor) Close() error

Close closes the rows iterator.

func (*RowsCursor) ColumnTypeScanType

func (rc *RowsCursor) ColumnTypeScanType(index int) reflect.Type

RowsColumnTypeScanType may be implemented by Rows. It should return the value type that can be used to scan types into.

func (*RowsCursor) Columns

func (rc *RowsCursor) Columns() []string

Columns returns the names of the columns.

func (*RowsCursor) HasNextResultSet

func (rc *RowsCursor) HasNextResultSet() bool

HasNextResultSet is called at the end of the current result set and reports whether there is another result set after the current one.

func (*RowsCursor) Next

func (rc *RowsCursor) Next(accumulator []driver.Value) error

Next is called to populate the next row of data into the provided slice.

func (*RowsCursor) NextResultSet

func (rc *RowsCursor) NextResultSet() error

NextResultSet advances the driver to the next result set even if there are remaining rows in the current result set.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL