Documentation
¶
Overview ¶
Package mockx provides a lightweight mocking utility for Go interfaces. It allows you to create mock implementations, register method behaviors and retrieve method arguments.
Example (Mockx) ¶
package main import ( "fmt" "github.com/AndreyArthur/mockx" ) type Greeter interface { Greet(name string) string } type GreeterMock struct { mockx.Mockx } func (greeter *GreeterMock) Greet(name string) string { values := greeter.Call("Greet", name) return mockx.Value[string](values[0]) } func main() { greeter := &GreeterMock{} greeter.Init((*Greeter)(nil)) greeter.Impl("Greet", func(name string) string { return "Hello, " + name + "!" }) result := greeter.Greet("Mockx") fmt.Printf("result = %q\n", result) }
Output: result = "Hello, Mockx!"
Example (Usage) ¶
Use the mockx library in tests.
package main import ( "errors" "fmt" "github.com/AndreyArthur/mockx" ) // Define a sorting interface. type Sorting interface { IsSorted(slice []int) (bool, error) } // Implement a Searcher struct that depends on the Sorting interface. type Searcher struct { sorting Sorting } func NewSearcher(sorting Sorting) *Searcher { return &Searcher{ sorting: sorting, } } func (searcher *Searcher) linear(slice []int, target int) int { for i, value := range slice { if value == target { return i } } return -1 } func (searcher *Searcher) binary(slice []int, target int) int { left, right := 0, len(slice)-1 for left <= right { mid := left + (right-left)/2 if slice[mid] == target { return mid } else if slice[mid] < target { left = mid + 1 } else { right = mid - 1 } } return -1 } func (searcher *Searcher) Search(slice []int, target int) int { sorted, err := searcher.sorting.IsSorted(slice) if err != nil { panic(err) } if sorted { return searcher.binary(slice, target) } return searcher.linear(slice, target) } // Define a Sorting mock struct. type SortingMock struct { mockx.Mockx } func NewSortingMock() *SortingMock { sorting := &SortingMock{} sorting.Init((*Sorting)(nil)) return sorting } func (sorting *SortingMock) IsSorted(slice []int) (bool, error) { values := sorting.Call("IsSorted", slice) return mockx.Value[bool](values[0]), mockx.Reference[error](values[1]) } // Use the mockx library in tests. func main() { sorting := NewSortingMock() searcher := NewSearcher(sorting) slice := []int{3, 1, 2, 5, 4} sorting.Return("IsSorted", false, nil) index := searcher.Search(slice, 3) fmt.Printf("index = %d\n", index) sorting.Return("IsSorted", true, nil) index = searcher.Search(slice, 3) fmt.Printf("index = %d\n", index) sorting.Impl("IsSorted", func(slice []int) (bool, error) { if slice == nil { return false, errors.New("Cannot verify, a nil slice was given.") } for i := range len(slice) - 1 { if slice[i] > slice[i+1] { return false, nil } } return true, nil }) index = searcher.Search(slice, 4) fmt.Printf("index = %d\n", index) }
Output: index = 0 index = -1 index = 4
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Reference ¶ added in v1.1.0
Reference is a helper function that handles the conversion of an any to a nillable type.
In Go, nillable types are:
Pointers - *T Slices - []T Maps - map[T]U Channels - chan T Functions - func(...) ... Interfaces - interface{} (Including custom interfaces)
The Reference function should be used to convert all of these types in mock method declaration, if not, you must handle the nil case manually.
Example ¶
package main import ( "fmt" "github.com/AndreyArthur/mockx" ) func main() { var untyped any = nil recovered := mockx.Reference[error](untyped) fmt.Printf("recovered = %v\n", recovered) }
Output: recovered = <nil>
func Value ¶ added in v1.1.0
Value is a helper function that handles the conversion of an any to a value (non-nillable) type.
In Go, non-nillable types are:
Integers - int, uint, int64, uint64... Floats - float32, float64 Booleans - bool Strings - string Arrays - [N]T Structs - struct{} (struct values, not pointers)
Using the Value function is not a must, but it helps to normalize your mock method declarations.
Example ¶
package main import ( "fmt" "github.com/AndreyArthur/mockx" ) func main() { var untyped any = 42 recovered := mockx.Value[int](untyped) fmt.Printf("recovered = %v\n", recovered) }
Output: recovered = 42
Types ¶
type Mockx ¶
type Mockx struct {
// contains filtered or unexported fields
}
Mockx is the main struct that manages mock method implementations and args tracking.
func (*Mockx) Args ¶
Args retrieves the arguments used in the most recent call to the specified method. Panics if the method was never called.
Example ¶
greeter := &GreeterMock{} greeter.Init((*Greeter)(nil)) greeter.Greet("Mockx") args := greeter.Args("Greet") arg := mockx.Value[string](args[0]) fmt.Printf("arg = %q\n", arg)
Output: arg = "Mockx"
func (*Mockx) Call ¶
Call invokes a registered mock method with the given arguments. Panics if the method is not registered.
Example ¶
greeter := &GreeterMock{} greeter.Init((*Greeter)(nil)) values := greeter.Call("Greet", "Mockx") result := mockx.Value[string](values[0]) fmt.Printf("result = %q\n", result)
Output: result = ""
func (*Mockx) Impl ¶
Impl manually registers a function as an implementation for a method. The provided function must match the signature of the method.
Example ¶
greeter := &GreeterMock{} greeter.Init((*Greeter)(nil)) greeter.Impl("Greet", func(name string) string { return "Welcome, " + name + "." }) result := greeter.Greet("Mockx") fmt.Printf("result = %q\n", result)
Output: result = "Welcome, Mockx."
func (*Mockx) Init ¶
Init populates the mock instance with zero-value implementations for all methods of the given interface.
It's not necessary to call Init into a Mockx instance, but if you don't, you need to manually call Impl or Return for all used methods, otherwise, your program will panic.
Example ¶
greeter := &GreeterMock{} greeter.Init((*Greeter)(nil)) result := greeter.Greet("Mockx") fmt.Printf("result = %q\n", result)
Output: result = ""