gormexpect

package module
v0.0.0-...-bca4501 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2021 License: MIT Imports: 14 Imported by: 0

README

Gorm Expect

A Go database testing library for use with gorm that doesn't involve a lot of pain.

GoDoc wercker status

Why

Testing gorm-based DALs is terrible. Most of the time, you have to use db.Debug() to print the SQL generated by gorm, escape it, generate mock sql.Rows, etc., and hope for the best. gormexpect wraps and mirrors (most of) the gorm API for superior DX.

Installation

go get -u github.com/iantanwx/gorm-expect

Usage

type User struct {
	Id           int64
	Age          int64
	Name         string `sql:"size:255"`
	Email        string
	Birthday     *time.Time // Time
	CreatedAt    time.Time  // CreatedAt: Time of record is created, will be insert automatically
	UpdatedAt    time.Time  // UpdatedAt: Time of record is updated, will be updated automatically
	Emails       []Email    // Embedded structs
	CreditCard   CreditCard
	Languages    []Language `gorm:"many2many:user_languages;"`
	PasswordHash []byte
}

type UserRepository struct {
  db *gorm.DB
}

func (r *UserRepository) FindByID(id int64) (User, error) {
	user := User{Id: id}
	err := r.db.Preload("Emails").Preload("CreditCard").Preload("Languages").Find(&user).Error
	return user, err
}

func TestUserRepoPreload1(t *testing.T) {
	db, expect, err := expecter.NewDefaultExpecter()
	defer db.Close()

	if err != nil {
		t.Fatal(err)
	}

	repo := &UserRepository{db}

	// has one
	creditCard := CreditCard{Number: "12345678"}
	// has many
	email := []Email{
		Email{Email: "fake_user@live.com"},
		Email{Email: "fake_user@gmail.com"},
	}
	// many to many
	languages := []Language{
		Language{Name: "EN"},
		Language{Name: "ZH"},
	}

	expected := User{
		Id:         1,
		Name:       "my_name",
		CreditCard: creditCard,
		Emails:     email,
		Languages:  languages,
	}

	expect.Preload("Emails").Preload("CreditCard").Preload("Languages").Find(&User{Id: 1}).Returns(expected)
	actual, err := repo.FindByID(1)

	assert.Nil(t, expect.AssertExpectations())
	assert.Nil(t, err)
	assert.Equal(t, expected, actual)
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Adapter

type Adapter interface {
	ExpectQuery(stmt Stmt) Queryer
	ExpectExec(stmt Stmt) Execer
	ExpectBegin() TxBeginner
	ExpectCommit() TxCommitter
	ExpectRollback() TxRollback
	AssertExpectations() error
}

Adapter provides an abstract interface over concrete mock database implementations (e.g. go-sqlmock or go-testdb)

func NewSqlmockAdapter

func NewSqlmockAdapter(dialect string, args ...interface{}) (*gorm.DB, Adapter, error)

NewSqlmockAdapter returns a mock gorm.DB and an Adapter backed by go-sqlmock

type AdapterFactory

type AdapterFactory func(dialect string, args ...interface{}) (*gorm.DB, Adapter, error)

AdapterFactory is a generic interface for arbitrary adapters that satisfy the interface. variadic args are passed to gorm.Open.

type ExecExpectation

type ExecExpectation interface {
	WillSucceed(lastReturnedID, rowsAffected int64) ExecExpectation
	WillFail(err error) ExecExpectation
}

ExecExpectation is returned by Expecter. It exposes a narrower API than Execer to limit footguns.

type ExecWrapper

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

ExecWrapper wraps ExecExpectation

func (*ExecWrapper) WillSucceed

func (w *ExecWrapper) WillSucceed(lastReturnID, rowsAffected int64)

WillSucceed has the same signature as ExecExpectation.WillSucceed. It is only returned from Append() and Replace().

type Execer

type Execer interface {
	WillSucceed(lastInsertID, rowsAffected int64) Execer
	WillFail(err error) Execer
	Args(args ...driver.Value) Execer
}

Execer is a high-level interface to the underlying mock db

type Expecter

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

Expecter is the exported struct used for setting expectations

func NewDefaultExpecter

func NewDefaultExpecter() (*gorm.DB, *Expecter, error)

NewDefaultExpecter returns a Expecter powered by go-sqlmock

func NewExpecter

func NewExpecter(fn AdapterFactory, dialect string, args ...interface{}) (*gorm.DB, *Expecter, error)

NewExpecter returns an Expecter for arbitrary adapters

func (*Expecter) AssertExpectations

func (h *Expecter) AssertExpectations() error

AssertExpectations checks if all expected Querys and Execs were satisfied.

func (*Expecter) Assign

func (h *Expecter) Assign(attrs ...interface{}) *Expecter

Assign will merge the given struct into the scope's value

func (*Expecter) Association

func (h *Expecter) Association(column string) *MockAssociation

Association starts association mode

func (*Expecter) Begin

func (h *Expecter) Begin() TxBeginner

Begin starts a mock transaction

func (*Expecter) Commit

func (h *Expecter) Commit() TxCommitter

Commit commits a mock transaction

func (*Expecter) Count

func (h *Expecter) Count(out interface{}) QueryExpectation

Count triggers a query

func (*Expecter) Create

func (h *Expecter) Create(model interface{}) ExecExpectation

Create mocks insertion of a model into the DB

func (*Expecter) Debug

func (h *Expecter) Debug() *Expecter

Debug logs out queries

func (*Expecter) Delete

func (h *Expecter) Delete(model interface{}, where ...interface{}) ExecExpectation

Delete does the same thing as gorm.Delete

func (*Expecter) Find

func (h *Expecter) Find(out interface{}, where ...interface{}) QueryExpectation

Find triggers a Query

func (*Expecter) First

func (h *Expecter) First(out interface{}, where ...interface{}) QueryExpectation

First triggers a Query

func (*Expecter) FirstOrCreate

func (h *Expecter) FirstOrCreate(out interface{}, returns interface{}, where ...interface{}) ExecExpectation

FirstOrCreate slightly differs from the equivalent Gorm method. It takes an extra argument (returns). If out and returns have the same type, returns is copied into out and nil is returned. The INSERT is not executed. If returns is nil, a not found error is set, and an ExecExpectation is returned.

func (*Expecter) FirstOrInit

func (h *Expecter) FirstOrInit(out interface{}, returns interface{}, where ...interface{}) *Expecter

FirstOrInit is similar to FirstOrCreate

func (*Expecter) Limit

func (h *Expecter) Limit(limit int) *Expecter

Limit sets limit parameter on query

func (*Expecter) Model

func (h *Expecter) Model(model interface{}) *Expecter

Model sets scope.Value

func (*Expecter) Not

func (h *Expecter) Not(query interface{}, args ...interface{}) *Expecter

Not sets a NOT condition(s)

func (*Expecter) Offset

func (h *Expecter) Offset(offset int) *Expecter

Offset sets offset parameter on query

func (*Expecter) Preload

func (h *Expecter) Preload(column string, conditions ...interface{}) *Expecter

Preload clones the expecter and sets a preload condition on gorm.DB

func (*Expecter) Rollback

func (h *Expecter) Rollback() TxRollback

Rollback rollsback a mock transaction

func (*Expecter) Save

func (h *Expecter) Save(model interface{}) ExecExpectation

Save mocks updating a record in the DB and will trigger db.Exec()

func (*Expecter) Skip

func (h *Expecter) Skip(hook string, callbackName string) *Expecter

Skip causes callbacks to be skipped

func (*Expecter) Update

func (h *Expecter) Update(attrs ...interface{}) ExecExpectation

Update mocks updating the given attributes in the DB

func (*Expecter) Updates

func (h *Expecter) Updates(values interface{}, ignoreProtectedAttrs ...bool) ExecExpectation

Updates does the same thing as Update, but with map or struct

func (*Expecter) Where

func (h *Expecter) Where(query interface{}, args ...interface{}) *Expecter

Where sets a WHERE condition(s)

type MockAssociation

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

MockAssociation mirros gorm.Association

func NewMockAssociation

func NewMockAssociation(c string, a *gorm.Association, e *Expecter) *MockAssociation

NewMockAssociation returns a MockAssociation

func (*MockAssociation) Append

func (a *MockAssociation) Append(values ...interface{}) *ExecWrapper

Append wraps gorm.Association.Append

func (*MockAssociation) Clear

func (a *MockAssociation) Clear() *ExecWrapper

Clear wraps gorm.Association.Clear

func (*MockAssociation) Count

func (a *MockAssociation) Count() *QueryWrapper

Count wraps gorm.Association.Count

func (*MockAssociation) Delete

func (a *MockAssociation) Delete(values ...interface{}) *ExecWrapper

Delete wraps gorm.Association.Delete

func (*MockAssociation) Find

func (a *MockAssociation) Find(value interface{}) *QueryWrapper

Find wraps gorm.Association

func (*MockAssociation) Replace

func (a *MockAssociation) Replace(values ...interface{}) *ExecWrapper

Replace wraps gorm.Association.Replace

type NoopConnection

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

NoopConnection implements sql/driver.Conn for our purposes, the noop connection never returns an error, as we only require it for generating queries. It is necessary because eager loading will fail if any operation returns an error

func (*NoopConnection) Begin

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

Begin implements sql/driver.Conn

func (*NoopConnection) Close

func (c *NoopConnection) Close() error

Close implements sql/driver.Conn

func (*NoopConnection) Commit

func (c *NoopConnection) Commit() error

Commit implements sql/driver.Conn

func (*NoopConnection) Exec

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

Exec implements sql/driver.Conn

func (*NoopConnection) Prepare

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

Prepare implements sql/driver.Conn

func (*NoopConnection) Query

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

Query implements sql/driver.Conn

func (*NoopConnection) ReturnExecResult

func (c *NoopConnection) ReturnExecResult(lastReturnedID, rowsAffected int64)

ReturnExecResult will cause the driver to return the passed values for the next call to Exec. It goes back to the default of 0, 0 thereafter.

func (*NoopConnection) ReturnNilRows

func (c *NoopConnection) ReturnNilRows()

ReturnNilRows instructs the noop driver to return empty rows for all queries until returnNilRows is set to false

func (*NoopConnection) Rollback

func (c *NoopConnection) Rollback() error

Rollback implements sql/driver.Conn

type NoopController

type NoopController interface {
	ReturnNilRows()
	ReturnExecResult(lastReturnedID, rowsAffected int64)
}

NoopController provides a crude interface for manipulating NoopConnection

func NewNoopDB

func NewNoopDB() (gorm.SQLCommon, NoopController, error)

NewNoopDB initialises a new DefaultNoopDB

type NoopDriver

type NoopDriver struct {
	sync.Mutex
	// contains filtered or unexported fields
}

NoopDriver implements sql/driver.Driver

func (*NoopDriver) Open

func (d *NoopDriver) Open(dsn string) (driver.Conn, error)

Open implements sql/driver.Driver

type NoopResult

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

NoopResult is a noop struct that satisfies sql.Result

func (NoopResult) LastInsertId

func (r NoopResult) LastInsertId() (int64, error)

LastInsertId is a noop method for satisfying drive.Result

func (NoopResult) RowsAffected

func (r NoopResult) RowsAffected() (int64, error)

RowsAffected is a noop method for satisfying drive.Result

type NoopRows

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

NoopRows implements driver.Rows

func (*NoopRows) Close

func (r *NoopRows) Close() error

Close implements driver.Rows

func (*NoopRows) Columns

func (r *NoopRows) Columns() []string

Columns implements driver.Rows

func (*NoopRows) Next

func (r *NoopRows) Next(dest []driver.Value) error

Next implements driver.Rows and alwys returns only one row

type NoopStmt

type NoopStmt struct{}

NoopStmt implements driver.Stmt

func (*NoopStmt) Close

func (s *NoopStmt) Close() error

Close implements driver.Stmt

func (*NoopStmt) Exec

func (s *NoopStmt) Exec(args []driver.Value) (driver.Result, error)

Exec implements driver.Stmt

func (*NoopStmt) NumInput

func (s *NoopStmt) NumInput() int

NumInput implements driver.Stmt

func (*NoopStmt) Query

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

Query implements driver.Stmt

type Operation

type Operation int

Operation represents the Association method being called. Behaviour internally changes depending on the operation.

const (
	Find Operation = iota
	Append
	Replace
	Delete
	Count
	Clear
)

type Preload

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

Preload mirrors gorm's search.searchPreload since it's private, we have to resort to some reflection black magic to make it work right. we'll just read from private field using reflect and copy the values into Preload.

type QueryExpectation

type QueryExpectation interface {
	Returns(value interface{}) *Expecter
}

QueryExpectation is returned by Expecter. It exposes a narrower API than Queryer to limit footguns.

type QueryWrapper

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

QueryWrapper is just a wrapper over QueryExpectation. This is necessary to allow MockAssociation to have a fluent API

func (*QueryWrapper) Returns

func (w *QueryWrapper) Returns(value interface{}) *MockAssociation

Returns functions in the same way as Expecter.Returns

type Queryer

type Queryer interface {
	Returns(rows interface{}) Queryer
	Errors(err error) Queryer
	Args(args ...driver.Value) Queryer
}

Queryer is returned from ExpectQuery it is used to control the mock database's response

type Recorder

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

Recorder satisfies the logger interface

func (*Recorder) GetFirst

func (r *Recorder) GetFirst() (Stmt, bool)

GetFirst returns the first recorded sql statement logged. If there are no statements, false is returned

func (*Recorder) IsEmpty

func (r *Recorder) IsEmpty() bool

IsEmpty returns true if the statements slice is empty

func (*Recorder) Record

func (r *Recorder) Record(stmt Stmt, shouldEscape bool)

Record records a Stmt for use when SQL is finally executed By default, it escapes with regexp.EscapeMeta

type SqlmockAdapter

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

SqlmockAdapter implemenets the Adapter interface using go-sqlmock it is the default Adapter

func (*SqlmockAdapter) AssertExpectations

func (a *SqlmockAdapter) AssertExpectations() error

AssertExpectations asserts that _all_ expectations for a test have been met and returns an error specifying which have not if there are unmet expectations

func (*SqlmockAdapter) ExpectBegin

func (a *SqlmockAdapter) ExpectBegin() TxBeginner

ExpectBegin mocks a sql transaction

func (*SqlmockAdapter) ExpectCommit

func (a *SqlmockAdapter) ExpectCommit() TxCommitter

ExpectCommit mocks committing a sql transaction

func (*SqlmockAdapter) ExpectExec

func (a *SqlmockAdapter) ExpectExec(exec Stmt) Execer

ExpectExec wraps the underlying mock method for setting a exec expectation

func (*SqlmockAdapter) ExpectQuery

func (a *SqlmockAdapter) ExpectQuery(query Stmt) Queryer

ExpectQuery wraps the underlying mock method for setting a query expectation. It accepts multiple statements in the event of preloading

func (*SqlmockAdapter) ExpectRollback

func (a *SqlmockAdapter) ExpectRollback() TxRollback

ExpectRollback mocks rolling back a sql

type SqlmockExecExpectation

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

SqlmockExecExpectation implement ExecExpectation with gosqlmock

func (*SqlmockExecExpectation) WillFail

func (e *SqlmockExecExpectation) WillFail(err error) ExecExpectation

WillFail sets the exec to fail with the passed error

func (*SqlmockExecExpectation) WillSucceed

func (e *SqlmockExecExpectation) WillSucceed(lastReturnedID, rowsAffected int64) ExecExpectation

WillSucceed sets the exec to be successful with the passed ID and rows. This method may also call Query, if there are default columns.

type SqlmockExecer

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

SqlmockExecer implements Execer with gosqlmock

func (*SqlmockExecer) Args

func (e *SqlmockExecer) Args(args ...driver.Value) Execer

Args sets the args that the statement should be executed with

func (*SqlmockExecer) WillFail

func (e *SqlmockExecer) WillFail(err error) Execer

WillFail simulates returning an Error from an unsuccessful exec

func (*SqlmockExecer) WillSucceed

func (e *SqlmockExecer) WillSucceed(lastReturnedID, rowsAffected int64) Execer

WillSucceed accepts a two int64s. They are passed directly to the underlying mock db. Useful for checking DAO behaviour in the event that the incorrect number of rows are affected by an Exec

type SqlmockQueryExpectation

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

SqlmockQueryExpectation implements QueryExpectation for go-sqlmock It gets a pointer to Expecter

func (*SqlmockQueryExpectation) Returns

func (q *SqlmockQueryExpectation) Returns(out interface{}) *Expecter

Returns accepts an out type which should either be a struct or slice. Under the hood, it converts a gorm model struct to sql.Rows that can be passed to the underlying mock db

type SqlmockQueryer

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

SqlmockQueryer implements Queryer

func (*SqlmockQueryer) Args

func (r *SqlmockQueryer) Args(args ...driver.Value) Queryer

Args sets the args that queries should be executed with

func (*SqlmockQueryer) Errors

func (r *SqlmockQueryer) Errors(err error) Queryer

Errors will return an error as the query result

func (*SqlmockQueryer) Returns

func (r *SqlmockQueryer) Returns(rows interface{}) Queryer

Returns will set the low level rows to be returned for a given set of queries

type SqlmockTxBeginner

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

SqlmockTxBeginner implements TxBeginner

func (*SqlmockTxBeginner) WillFail

func (b *SqlmockTxBeginner) WillFail(err error) TxBeginner

WillFail implements TxBeginner

type SqlmockTxCommitter

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

SqlmockTxCommitter implements TxCommitter

func (*SqlmockTxCommitter) WillFail

func (c *SqlmockTxCommitter) WillFail(err error) TxCommitter

WillFail implements TxCommitter

type SqlmockTxRollback

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

SqlmockTxCloser implement TxCloser

func (*SqlmockTxRollback) WillFail

func (c *SqlmockTxRollback) WillFail(err error) TxRollback

WillFail implements TxCloser

type Stmt

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

Stmt represents a sql statement. It can be an Exec, Query, or QueryRow

type TxBeginner

type TxBeginner interface {
	WillFail(err error) TxBeginner
}

TxBeginner is an interface to underlying sql.Driver mock implementation

type TxCommitter

type TxCommitter interface {
	WillFail(err error) TxCommitter
}

TxCommitter is an interface to underlying mock implementation's tx.Commit

type TxRollback

type TxRollback interface {
	WillFail(err error) TxRollback
}

TxRollback is an interface to underlying mock implementation's tx.Rollback

Jump to

Keyboard shortcuts

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