The mock package provides a comprehensive system for creating mock objects and verifying method calls in tests. It enables you to set expectations on method calls, configure return values, and verify that your code interacts with dependencies correctly.
import "github.com/stretchr/testify/mock"import "github.com/stretchr/testify/mock"The mock package is built around embedding a Mock object in your test structs. Here's a complete example:
import (
"testing"
"github.com/stretchr/testify/mock"
)
// MyInterface defines the interface we want to mock
type MyInterface interface {
DoSomething(x int, y string) (bool, error)
}
// MyMock embeds mock.Mock to track calls and expectations
type MyMock struct {
mock.Mock
}
// DoSomething implements MyInterface by delegating to the mock
func (m *MyMock) DoSomething(x int, y string) (bool, error) {
args := m.Called(x, y)
return args.Bool(0), args.Error(1)
}
// Test function showing mock setup and verification
func TestMyCode(t *testing.T) {
// Create mock instance
mockObj := new(MyMock)
// Set up expectations
mockObj.On("DoSomething", 5, "hello").Return(true, nil)
// Use the mock in your code
result, err := mockObj.DoSomething(5, "hello")
// Verify expectations were met
mockObj.AssertExpectations(t)
}The Mock type is the foundation of the mocking system. It tracks method calls and expectations.
type Mock struct {
// ExpectedCalls represents the calls that are expected of an object
ExpectedCalls []*Call
// Calls holds the calls that were made to this mocked object
Calls []Call
}Setting Up Expectations:
func (m *Mock) On(methodName string, arguments ...interface{}) *CallStarts a description of an expectation for the specified method being called.
Example:
mock.On("MyMethod", arg1, arg2)Recording Method Calls:
func (m *Mock) Called(arguments ...interface{}) ArgumentsTells the mock object that a method has been called, and gets an array of arguments to return. Panics if the call is unexpected (i.e. not preceded by appropriate .On().Return() calls). If Call.WaitFor is set, blocks until the channel is closed or receives a message.
func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) ArgumentsAlternative to Called() that explicitly specifies the method name. Tells the mock object that the given method has been called, and gets an array of arguments to return.
Verification Methods:
func (m *Mock) AssertExpectations(t TestingT) boolAsserts that everything specified with On and Return was in fact called as expected. Calls may have occurred in any order.
func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) boolAsserts that the method was called with the specified arguments. It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) boolAsserts that the method was not called with the specified arguments. It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) boolAsserts that the method was called exactly the specified number of times.
Utility Methods:
func (m *Mock) TestData() objx.MapReturns a map that holds any data that might be useful for testing. Testify ignores this data completely, allowing you to store whatever you like.
func (m *Mock) Test(t TestingT)Sets the TestingT on which errors will be reported, otherwise errors will cause a panic. Test should not be called on an object that is going to be used in a goroutine other than the one running the test function.
func (m *Mock) IsMethodCallable(t TestingT, methodName string, arguments ...interface{}) boolChecks whether the method can be called. If the method was called more than its configured Repeatability, returns false.
func (m *Mock) String() stringProvides a %v format string for Mock. Note: this is used implicitly by Arguments.Diff if a Mock is passed. It exists because Go's default %v formatting traverses the struct without acquiring the mutex, which is detected by go test -race.
The Call type represents a method call expectation and provides methods for configuring return values, call counts, timing, and more.
type Call struct {
Parent *Mock
// Method is the name of the method that was or will be called
Method string
// Arguments holds the arguments of the method
Arguments Arguments
// ReturnArguments holds the arguments that should be returned when
// this method is called
ReturnArguments Arguments
// Repeatability is the number of times to return the return arguments
// when setting expectations. 0 means to always return the value.
Repeatability int
// WaitFor holds a channel that will be used to block the Return until
// it either receives a message or is closed. nil means it returns immediately.
WaitFor <-chan time.Time
// RunFn holds a handler used to manipulate arguments content that are
// passed by reference. It's useful when mocking methods such as
// unmarshalers or decoders.
RunFn func(Arguments)
// PanicMsg holds msg to be used to mock panic on the function call.
// If the PanicMsg is set to a non-nil string, the function call will panic
// irrespective of other settings.
PanicMsg *string
}Return Value Configuration:
func (c *Call) Return(returnArguments ...interface{}) *CallSpecifies the return arguments for the expectation.
Example:
Mock.On("DoSomething").Return(errors.New("failed"))func (c *Call) Run(fn func(args Arguments)) *CallSets a handler to be called before returning. It can be used when mocking a method (such as an unmarshaler) that takes a pointer to a struct and sets properties in such struct.
Example:
Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}")).Return().Run(func(args Arguments) {
arg := args.Get(0).(*map[string]interface{})
arg["foo"] = "bar"
})Call Count Expectations:
func (c *Call) Once() *CallIndicates that the mock should only return the value once.
Example:
Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()func (c *Call) Twice() *CallIndicates that the mock should only return the value twice.
Example:
Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()func (c *Call) Times(i int) *CallIndicates that the mock should only return the value the specified number of times.
Example:
Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)func (c *Call) Maybe() *CallAllows the method call to be optional. Not calling an optional method will not cause an error while asserting expectations.
Timing and Ordering:
func (c *Call) After(d time.Duration) *CallSets how long to block until the call returns.
Example:
Mock.On("MyMethod", arg1, arg2).After(time.Second)func (c *Call) WaitUntil(w <-chan time.Time) *CallSets the channel that will block the mock's return until it's closed or a message is received.
Example:
Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second))func (c *Call) NotBefore(calls ...*Call) *CallIndicates that the mock should only be called after the referenced calls have been called as expected. The referenced calls may be from the same mock instance and/or other mock instances.
Example:
Mock.On("Do").Return(nil).NotBefore(
Mock.On("Init").Return(nil)
)Panic Configuration:
func (c *Call) Panic(msg string) *CallSpecifies that the function call should panic with the given message.
Example:
Mock.On("DoSomething").Panic("test panic")Call Management:
func (c *Call) On(methodName string, arguments ...interface{}) *CallChains a new expectation description onto the mocked interface. This allows fluent syntax.
Example:
Mock.
On("MyMethod", 1).Return(nil).
On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error"))func (c *Call) Unset() *CallRemoves all mock handlers that satisfy the call instance arguments from being called. Only supported on call instances with static input arguments.
Example:
Mock.
On("MyMethod", 2, 2).Return(0).
On("MyMethod", 3, 3).Return(0).
On("MyMethod", Anything, Anything).Return(0)
Mock.On("MyMethod", 3, 3).Unset()
// Only "MyMethod(2, 2)" handler remainsArguments represents method arguments or return values and provides type-safe accessors.
type Arguments []interface{}Accessing Arguments:
func (args Arguments) Get(index int) interface{}Returns the argument at the specified index.
func (args Arguments) String(indexOrNil ...int) stringGets the argument at the specified index as a string. Panics if there is no argument, or if the argument is of the wrong type.
If no index is provided, String() returns a complete string representation of the arguments.
func (args Arguments) Int(index int) intGets the argument at the specified index as an int. Panics if there is no argument, or if the argument is of the wrong type.
func (args Arguments) Bool(index int) boolGets the argument at the specified index as a bool. Panics if there is no argument, or if the argument is of the wrong type.
func (args Arguments) Error(index int) errorGets the argument at the specified index as an error. Panics if there is no argument, or if the argument is of the wrong type.
Comparison and Verification:
func (args Arguments) Is(objects ...interface{}) boolGets whether the objects match the arguments specified.
func (args Arguments) Diff(objects []interface{}) (string, int)Gets a string describing the differences between the arguments and the specified objects. Returns the diff string and number of differences found.
func (args Arguments) Assert(t TestingT, objects ...interface{}) boolCompares the arguments with the specified objects and fails the test if they do not exactly match.
Argument matchers provide flexible matching for expected method arguments.
Anything Matcher:
const Anything = "mock.Anything"Used in Diff and Assert when the argument being tested shouldn't be taken into consideration. Matches any argument value.
Example:
Mock.On("MyMethod", Anything, 42).Return(nil)Type-Based Matchers:
type AnythingOfTypeArgument = anythingOfTypeArgument
func AnythingOfType(t string) AnythingOfTypeArgumentReturns a special value containing the name of the type to check for. The type name will be matched against the type name returned by reflect.Type.String().
Example:
args.Assert(t, AnythingOfType("string"), AnythingOfType("int"))
Mock.On("Do", mock.AnythingOfType("string"))type IsTypeArgument struct {
// contains unexported fields
}
func IsType(t interface{}) *IsTypeArgumentReturns an IsTypeArgument object containing the type to check for. You can provide a zero-value of the type to check. This is an alternative to AnythingOfType.
Example:
args.Assert(t, IsType(""), IsType(0))Custom Matcher:
func MatchedBy(fn interface{}) argumentMatcherCan be used to match a mock call based on only certain properties from a complex struct or some calculation. It takes a function that will be evaluated with the called argument and will return true when there's a match and false otherwise.
The function fn must accept a single argument (of the expected type) and return a bool. If fn doesn't match the required signature, MatchedBy() panics.
Example:
m.On("Do", MatchedBy(func(req *http.Request) bool {
return req.Host == "example.com"
}))Functional Options Matcher:
type FunctionalOptionsArgument struct {
// contains unexported fields
}
func FunctionalOptions(values ...interface{}) *FunctionalOptionsArgumentReturns a FunctionalOptionsArgument object containing the expected functional-options to check for.
Example:
args.Assert(t, FunctionalOptions(foo.Opt1("strValue"), foo.Opt2(613)))func (f *FunctionalOptionsArgument) String() stringReturns the string representation of FunctionalOptionsArgument.
func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) boolAsserts that everything specified with On and Return of the specified objects was in fact called as expected. Calls may have occurred in any order.
func InOrder(calls ...*Call)Defines the order in which the calls should be made.
Example:
InOrder(
Mock.On("init").Return(nil),
Mock.On("Do").Return(nil),
)type TestingT interface {
Logf(format string, args ...interface{})
Errorf(format string, args ...interface{})
FailNow()
}TestingT is an interface wrapper around *testing.T and *testing.B.
import (
"testing"
"github.com/stretchr/testify/mock"
)
// Define interface to mock
type Database interface {
Save(key string, value interface{}) error
Load(key string) (interface{}, error)
}
// Create mock implementation
type MockDatabase struct {
mock.Mock
}
func (m *MockDatabase) Save(key string, value interface{}) error {
args := m.Called(key, value)
return args.Error(0)
}
func (m *MockDatabase) Load(key string) (interface{}, error) {
args := m.Called(key)
return args.Get(0), args.Error(1)
}
// Test using the mock
func TestDatabaseOperations(t *testing.T) {
mockDB := new(MockDatabase)
// Set up expectations
mockDB.On("Save", "user:123", mock.Anything).Return(nil)
mockDB.On("Load", "user:123").Return("John Doe", nil)
// Execute code under test
err := mockDB.Save("user:123", "John Doe")
if err != nil {
t.Fatal(err)
}
result, err := mockDB.Load("user:123")
if err != nil {
t.Fatal(err)
}
// Verify expectations
mockDB.AssertExpectations(t)
mockDB.AssertCalled(t, "Save", "user:123", mock.Anything)
if result != "John Doe" {
t.Errorf("Expected 'John Doe', got %v", result)
}
}func TestCallCounts(t *testing.T) {
mockDB := new(MockDatabase)
// Expect Save to be called exactly twice
mockDB.On("Save", "config", mock.Anything).Return(nil).Twice()
// Expect Load to be called at least once (optional expectations)
mockDB.On("Load", "settings").Return("default", nil).Maybe()
// Execute operations
mockDB.Save("config", "value1")
mockDB.Save("config", "value2")
// Verify expectations (will pass because Load was optional)
mockDB.AssertExpectations(t)
mockDB.AssertNumberOfCalls(t, "Save", 2)
}import "net/http"
type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}
type MockHTTPClient struct {
mock.Mock
}
func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error) {
args := m.Called(req)
return args.Get(0).(*http.Response), args.Error(1)
}
func TestCustomMatcher(t *testing.T) {
mockClient := new(MockHTTPClient)
// Match requests to specific host
mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool {
return req.Host == "api.example.com"
})).Return(&http.Response{StatusCode: 200}, nil)
// Create request
req, _ := http.NewRequest("GET", "https://api.example.com/data", nil)
// Execute
resp, err := mockClient.Do(req)
// Verify
if err != nil {
t.Fatal(err)
}
if resp.StatusCode != 200 {
t.Errorf("Expected status 200, got %d", resp.StatusCode)
}
mockClient.AssertExpectations(t)
}type JSONDecoder interface {
Decode(v interface{}) error
}
type MockDecoder struct {
mock.Mock
}
func (m *MockDecoder) Decode(v interface{}) error {
args := m.Called(v)
return args.Error(0)
}
func TestDecoderWithSideEffects(t *testing.T) {
mockDecoder := new(MockDecoder)
// Use Run to populate the passed-in struct
mockDecoder.On("Decode", mock.AnythingOfType("*map[string]interface{}")).
Return(nil).
Run(func(args mock.Arguments) {
// Modify the argument that was passed in
m := args.Get(0).(*map[string]interface{})
(*m)["name"] = "John"
(*m)["age"] = 30
})
// Execute
result := make(map[string]interface{})
err := mockDecoder.Decode(&result)
// Verify
if err != nil {
t.Fatal(err)
}
if result["name"] != "John" || result["age"] != 30 {
t.Errorf("Unexpected result: %v", result)
}
mockDecoder.AssertExpectations(t)
}func TestTimingControl(t *testing.T) {
mockDB := new(MockDatabase)
// Simulate slow operation
mockDB.On("Load", "slow-key").
Return("data", nil).
After(100 * time.Millisecond)
// Measure execution time
start := time.Now()
mockDB.Load("slow-key")
duration := time.Since(start)
if duration < 100*time.Millisecond {
t.Error("Expected operation to take at least 100ms")
}
mockDB.AssertExpectations(t)
}func TestCallOrdering(t *testing.T) {
mockDB := new(MockDatabase)
// Define expected call order
initCall := mockDB.On("Save", "init", "true").Return(nil)
processCall := mockDB.On("Save", "status", "processing").Return(nil).NotBefore(initCall)
mockDB.On("Save", "status", "complete").Return(nil).NotBefore(processCall)
// Execute in correct order
mockDB.Save("init", "true")
mockDB.Save("status", "processing")
mockDB.Save("status", "complete")
// Verify expectations
mockDB.AssertExpectations(t)
}
// Alternative using InOrder
func TestInOrder(t *testing.T) {
mockDB := new(MockDatabase)
mock.InOrder(
mockDB.On("Save", "init", "true").Return(nil),
mockDB.On("Save", "status", "processing").Return(nil),
mockDB.On("Save", "status", "complete").Return(nil),
)
// Execute in correct order
mockDB.Save("init", "true")
mockDB.Save("status", "processing")
mockDB.Save("status", "complete")
mockDB.AssertExpectations(t)
}func TestPanicExpectation(t *testing.T) {
mockDB := new(MockDatabase)
// Configure mock to panic
mockDB.On("Save", "invalid", mock.Anything).Panic("database connection lost")
// Test panic behavior
defer func() {
if r := recover(); r == nil {
t.Error("Expected panic but didn't get one")
}
}()
mockDB.Save("invalid", "data")
}func TestMultipleMocks(t *testing.T) {
mockDB := new(MockDatabase)
mockCache := new(MockDatabase) // Using same type for example
// Set up expectations on both mocks
mockDB.On("Save", "user:123", "John").Return(nil)
mockCache.On("Save", "user:123", "John").Return(nil)
// Execute operations
mockDB.Save("user:123", "John")
mockCache.Save("user:123", "John")
// Verify all mocks at once
mock.AssertExpectationsForObjects(t, mockDB, mockCache)
}func TestAdvancedMatching(t *testing.T) {
mockDB := new(MockDatabase)
// Match any string for key, specific type for value
mockDB.On("Save",
mock.AnythingOfType("string"),
mock.IsType(&User{}),
).Return(nil)
// Match with Anything constant
mockDB.On("Load", mock.Anything).Return(nil, nil)
// Execute with various arguments
mockDB.Save("user:1", &User{Name: "John"})
mockDB.Save("user:2", &User{Name: "Jane"})
mockDB.Load("any-key")
mockDB.AssertExpectations(t)
}
type User struct {
Name string
}