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 = ""