### Install Mockey Go Library Source: https://context7.com/bytedance/mockey/llms.txt Install the Mockey library using Go modules. ```bash go get github.com/bytedance/mockey@latest ``` -------------------------------- ### Mock Functions and Methods Source: https://github.com/bytedance/mockey/blob/main/README.md Examples of mocking standard functions, methods with value receivers, and methods with pointer receivers. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Foo(in string) string { return in } type A struct{} func (a A) Foo(in string) string { return in } type B struct{} func (b *B) Foo(in string) string { return in } func main() { // mock function Mock(Foo).Return("MOCKED!").Build() fmt.Println(Foo("anything")) // MOCKED! // mock method (value receiver) Mock(A.Foo).Return("MOCKED!").Build() fmt.Println(A{}.Foo("anything")) // MOCKED! // mock method (pointer receiver) Mock((*B).Foo).Return("MOCKED!").Build() fmt.Println(new(B).Foo("anything")) // MOCKED! // Tips: if the target has no return value, you still need to call the empty `Return()` or use `To` to customize the hook function. } ``` -------------------------------- ### Mocking Interface Methods using GetMethod Source: https://github.com/bytedance/mockey/blob/main/README.md To mock a method on an interface type, use `GetMethod` to retrieve the method from an instance and then mock it. This example demonstrates mocking the `Foo` method of `FooI`. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) type FooI interface { Foo(string) string } func NewFoo() FooI { return &foo{} } // foo the original implementation of 'FooI' type foo struct{} func (f *foo) Foo(in string) string { return in } func main() { // get the original implementation and mock it instance := NewFoo() Mock(GetMethod(instance, "Foo")).Return("MOCKED!").Build() fmt.Println(instance.Foo("anything")) // MOCKED! } ``` -------------------------------- ### Mocking Interface Methods with Dummy Implementation Source: https://github.com/bytedance/mockey/blob/main/README.md An alternative approach to mocking interface methods is to create a dummy implementation and mock the constructor to return this dummy. This example mocks `NewFoo` to return a dummy `foo` struct. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) type FooI interface { Foo(string) string } func NewFoo() FooI { return &foo{} } // foo the original implementation of 'FooI' type foo struct{} func (f *foo) Foo(in string) string { return in } func main() { // generate a dummy implementation of 'FooI' and mock it type foo struct{ FooI } Mock((*foo).Foo).Return("MOCKED!").Build() // mock the constructor of 'FooI' to return the dummy implementation Mock(NewFoo).Return(new(foo)).Build() fmt.Println(NewFoo().Foo("anything")) // MOCKED! } ``` -------------------------------- ### Create a new feature branch Source: https://github.com/bytedance/mockey/blob/main/CONTRIBUTING.md Use this command to start a new development branch based on the develop branch. ```bash git checkout -b my-fix-branch develop ``` -------------------------------- ### MockGeneric - Mock Generic Functions and Methods in Go Source: https://context7.com/bytedance/mockey/llms.txt Mock generic functions and methods using MockGeneric. For Go 1.20+, the regular Mock function can also automatically detect generics. This example shows mocking a generic function and a generic method on a struct. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Transform[T any](input T) T { return input } type Container[T any] struct{} func (c *Container[T]) Get(key string) T { var zero T return zero } func main() { // Mock generic function with specific type MockGeneric(Transform[string]).Return("MOCKED").Build() fmt.Println(Transform("hello")) // Output: MOCKED fmt.Println(Transform(123)) // Output: 123 (different type, not mocked) // Mock generic method MockGeneric((*Container[int]).Get).Return(42).Build() c := &Container[int]{} fmt.Println(c.Get("key")) // Output: 42 } ``` -------------------------------- ### Identify nil pointer dereference Source: https://github.com/bytedance/mockey/blob/main/README.md Example of code that triggers an invalid memory address error due to an uninitialized interface. ```go type Loader interface{ Foo() } var loader Loader loader.Foo() // invalid memory address or nil pointer dereference ``` -------------------------------- ### Mock Variadic Functions and Methods Source: https://github.com/bytedance/mockey/blob/main/README.md Shows how to mock functions and methods that accept variadic arguments. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func FooVariadic(in ...string) string { return in[0] } type A struct{} func (a A) FooVariadic(in ...string) string { return in[0] } func main() { // mock variadic function Mock(FooVariadic).Return("MOCKED!").Build() fmt.Println(FooVariadic("anything")) // MOCKED! // mock variadic method Mock(A.FooVariadic).Return("MOCKED!").Build() fmt.Println(A{}.FooVariadic("anything")) // MOCKED! } ``` -------------------------------- ### Unit Test with Mockey Source: https://github.com/bytedance/mockey/blob/main/README.md Shows how to use Mockey with goconvey for unit testing. ```go package main_test import ( "math/rand" "testing" . "github.com/bytedance/mockey" . "github.com/smartystreets/goconvey/convey" ) // Win function to be tested, input a number, win if it's greater than random number, otherwise lose func Win(in int) bool { return in > rand.Int() } func TestWin(t *testing.T) { PatchConvey("TestWin", t, func() { Mock(rand.Int).Return(100).Build() // mock res1 := Win(101) // execute So(res1, ShouldBeTrue) // assert res2 := Win(99) // execute So(res2, ShouldBeFalse) // assert }) } ``` -------------------------------- ### Mock Interface Methods Source: https://context7.com/bytedance/mockey/llms.txt Demonstrates mocking interface methods globally or filtered by type and package using the exp/iface package. ```go package main import ( "bytes" "fmt" "io" . "github.com/bytedance/mockey/exp/iface" ) func main() { // Mock Read method for ALL io.Reader implementations Mock(io.Reader.Read).Return(5, io.EOF).Build() reader1 := bytes.NewReader(nil) reader2 := bytes.NewBufferString("") data := make([]byte, 10) n1, err1 := reader1.Read(data) n2, err2 := reader2.Read(data) fmt.Println(n1, err1) // Output: 5 EOF fmt.Println(n2, err2) // Output: 5 EOF // Mock only specific implementation types Mock(io.Reader.Read, SelectType("Reader"), SelectPkg("bytes")). Return(10, nil). Build() // Only bytes.Reader is mocked now n1, _ = bytes.NewReader(nil).Read(data) n2, _ = bytes.NewBufferString("").Read(data) fmt.Println(n1) // Output: 10 (mocked) fmt.Println(n2) // Output: 0 (not mocked, filtered out) } ``` -------------------------------- ### Verify Build() and Return()/To() Calls in Mockey Source: https://github.com/bytedance/mockey/blob/main/README.md Ensure that `Build()` is called and either `Return(xxx)` or `To(xxx)` is used. For functions without return values, an empty `Return()` or `To` with a custom hook is necessary. ```go package main_test import ( "fmt" "testing" . "github.com/bytedance/mockey" ) type A struct{} func (a A) Foo(in string) string { return in } func TestXXX(t *testing.T) { Mock((*A).Foo).Return("MOCKED!").Build() fmt.Println(A{}.Foo("anything")) // won't work, because the mock target should be `A.Foo` a := A{} Mock(a.Foo).Return("MOCKED!").Build() fmt.Println(a.Foo("anything")) // won't work, because the mock target should be `A.Foo` } ``` -------------------------------- ### Mock a Function Source: https://github.com/bytedance/mockey/blob/main/README.md Demonstrates the simplest usage of Mockey to override a function return value. ```go package main import ( "fmt" "math/rand" . "github.com/bytedance/mockey" ) func main() { Mock(rand.Int).Return(1).Build() // mock `rand.Int` to return 1 fmt.Printf("rand.Int() always return: %v\n", rand.Int()) // Try if it's still random? } ``` -------------------------------- ### Use Hook Functions with To Source: https://github.com/bytedance/mockey/blob/main/README.md Demonstrates using the To method to provide a custom implementation for a mocked function or method. Hook functions must match the original signature, though method receivers can be included or omitted. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Foo(in string) string { return in } type A struct { prefix string } func (a A) Foo(in string) string { return a.prefix + ":" + in } func main() { // NOTE: hook function must have the same function signature as the original function! Mock(Foo).To(func(in string) string { return "MOCKED!" }).Build() fmt.Println(Foo("anything")) // MOCKED! // NOTE: for method mocking, the receiver can be added to the signature of the hook function on your need (if the receiver is not used, it can be omitted, and mockey is compatible). Mock(A.Foo).To(func(a A, in string) string { return a.prefix + ":inner:" + "MOCKED!" }).Build() fmt.Println(A{prefix: "prefix"}.Foo("anything")) // prefix:inner:MOCKED! } ``` -------------------------------- ### Mock Functions and Methods in Go Source: https://context7.com/bytedance/mockey/llms.txt Use the Mock function to create mocks for functions, methods (value and pointer receivers), and standard library functions. Call Build() to activate the mock. ```go package main import ( "fmt" "math/rand" . "github.com/bytedance/mockey" ) func Foo(in string) string { return in } type A struct{} func (a A) Foo(in string) string { return in } type B struct{} func (b *B) Foo(in string) string { return in } func main() { // Mock a simple function Mock(Foo).Return("MOCKED!").Build() fmt.Println(Foo("anything")) // Output: MOCKED! // Mock a method with value receiver Mock(A.Foo).Return("MOCKED!").Build() fmt.Println(A{}.Foo("anything")) // Output: MOCKED! // Mock a method with pointer receiver Mock((*B).Foo).Return("MOCKED!").Build() fmt.Println(new(B).Foo("anything")) // Output: MOCKED! // Mock stdlib function Mock(rand.Int).Return(42).Build() fmt.Println(rand.Int()) // Output: 42 } ``` -------------------------------- ### Mock All Implementations of an Interface Method Source: https://github.com/bytedance/mockey/blob/main/README_cn.md Mock all implementations of a specific interface method. This is useful when you want to ensure a consistent behavior across all types that implement a given interface, regardless of their specific implementation details. Ensure the `exp/iface` package is imported. ```go package main import ( "bytes" "fmt" "io" "net" "os" . "github.com/bytedance/mockey/exp/iface" ) func main() { // Mock 所有的 Reader 接口的实现类型的 Read 方法 Mock(io.Reader.Read).Return(1, io.EOF).Build() reader1 := bytes.NewReader(nil) reader2 := bytes.NewBufferString("") reader3 := new(net.TCPConn) reader4 := new(os.File) fmt.Println(io.ReadAll(reader1)) // [0] , mocked fmt.Println(io.ReadAll(reader2)) // [0] , mocked fmt.Println(io.ReadAll(reader3)) // [0] , mocked fmt.Println(io.ReadAll(reader4)) // [0] , mocked } ``` -------------------------------- ### Mockey - Mock Functions and Methods Source: https://context7.com/bytedance/mockey/llms.txt Demonstrates how to use the Mock function to create mocks for regular functions, struct methods (value and pointer receivers), and standard library functions. The Mock function returns a MockBuilder to define mock behavior. ```APIDOC ## Mock - Mock Functions and Methods ### Description The `Mock` function creates a mock for any function or method. It returns a `MockBuilder` that allows you to define mock behavior using a fluent API. The mock becomes active after calling `Build()`. ### Method `Mock` ### Endpoint N/A (Function/Method Mocking) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go package main import ( "fmt" "math/rand" . "github.com/bytedance/mockey" ) func Foo(in string) string { return in } type A struct{} func (a A) Foo(in string) string { return in } type B struct{} func (b *B) Foo(in string) string { return in } func main() { // Mock a simple function Mock(Foo).Return("MOCKED!").Build() fmt.Println(Foo("anything")) // Output: MOCKED! // Mock a method with value receiver Mock(A.Foo).Return("MOCKED!").Build() fmt.Println(A{}.Foo("anything")) // Output: MOCKED! // Mock a method with pointer receiver Mock((*B).Foo).Return("MOCKED!").Build() fmt.Println(new(B).Foo("anything")) // Output: MOCKED! // Mock stdlib function Mock(rand.Int).Return(42).Build() fmt.Println(rand.Int()) // Output: 42 } ``` ### Response #### Success Response (N/A) N/A #### Response Example N/A ``` -------------------------------- ### Update Mockey for Memory Statistics and Index Errors Source: https://github.com/bytedance/mockey/blob/main/README_cn.md Errors like 'mappedReady and other memstats are not equal', 'index out of range', or 'invalid reference to runtime.sysAlloc' indicate an outdated Mockey version. Upgrade to the latest version. ```text mappedReady and other memstats are not equal index out of range invalid reference to runtime.sysAlloc ``` -------------------------------- ### Mockey - Return Mock Values Source: https://context7.com/bytedance/mockey/llms.txt Explains how to use the `Return` method on a `MockBuilder` to specify the exact values a mocked function or method should return, including handling errors. ```APIDOC ## Return - Specify Mock Return Values ### Description The `Return` method specifies the values that the mocked function should return. The return values must match the function's return signature. ### Method `Return` (on MockBuilder) ### Endpoint N/A (Function/Method Mocking) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go package main import ( "errors" "fmt" . "github.com/bytedance/mockey" ) func GetUser(id int) (string, error) { // Real implementation would fetch from database return "", errors.New("not implemented") } func main() { // Mock with single return value Mock(GetUser).Return("John Doe", nil).Build() name, err := GetUser(1) fmt.Println(name, err) // Output: John Doe // Mock with error return Mock(GetUser).Return("", errors.New("user not found")).Build() name, err = GetUser(999) fmt.Println(name, err) // Output: user not found } ``` ### Response #### Success Response (N/A) N/A #### Response Example N/A ``` -------------------------------- ### Manage Mocker instances in Go Source: https://github.com/bytedance/mockey/blob/main/README.md Acquire a Mocker instance to track call counts, remock, or release mocks dynamically. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Foo(in string) string { return in } func main() { mocker := Mock(Foo).When(func(in string) bool { return len(in) > 5 }).Return("MOCKED!").Build() fmt.Println(Foo("any")) // any fmt.Println(Foo("anything")) // MOCKED! // use `MockTimes` and `Times` to track the number of times mock worked and `Foo` is called fmt.Println(mocker.MockTimes()) // 1 fmt.Println(mocker.Times()) // 2 // Tips: When remocking or releasing mock, the related counters will be reset to 0. // remock `Foo` to return "MOCKED2!" mocker.Return("MOCKED2!") fmt.Println(Foo("anything")) // MOCKED2! fmt.Println(mocker.MockTimes()) // 1 | Reset to 0 when remocking // release `Foo` mock mocker.Release() fmt.Println(Foo("anything")) // anything | mock won't work, because mock released fmt.Println(mocker.MockTimes()) // 0 | Reset to 0 when releasing } ``` -------------------------------- ### Sequence Return Values for Mocked Functions Source: https://github.com/bytedance/mockey/blob/main/README_cn.md Mock a function to return a sequence of predefined values using `Sequence`. The `Then` method adds values to the sequence, and `Times` specifies how many times a value should be repeated before moving to the next. Ensure the `mockey` package is imported. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Foo(in string) string { return in } func main() { Mock(Foo).Return(Sequence("Alice").Then("Bob").Times(2).Then("Tom")).Build() fmt.Println(Foo("anything")) // Alice fmt.Println(Foo("anything")) // Bob fmt.Println(Foo("anything")) // Bob fmt.Println(Foo("anything")) // Tom } ``` -------------------------------- ### Sequence - Sequential Return Values in Go Source: https://context7.com/bytedance/mockey/llms.txt Use Sequence to define a series of return values for successive calls to a mocked function. The sequence cycles back to the first value after all values are exhausted. Use Times() to repeat a value before proceeding to the next. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func FetchData() string { return "real-data" } func main() { // Return different values on successive calls Mock(FetchData).Return(Sequence("first").Then("second").Then("third")).Build() fmt.Println(FetchData()) // Output: first fmt.Println(FetchData()) // Output: second fmt.Println(FetchData()) // Output: third fmt.Println(FetchData()) // Output: first (cycles back) // Use Times() to repeat a value multiple times Mock(FetchData).Return(Sequence("retry").Times(3).Then("success")).Build() fmt.Println(FetchData()) // Output: retry fmt.Println(FetchData()) // Output: retry fmt.Println(FetchData()) // Output: retry fmt.Println(FetchData()) // Output: success } ``` -------------------------------- ### Ensure Correct Compilation Flags for Mockey Source: https://github.com/bytedance/mockey/blob/main/README.md If Mockey fails, ensure that inline and compilation optimizations are disabled by adding `-gcflags="all=-N -l"` to your build command. This log indicates a potential issue. ```go Mockey check failed, please add -gcflags="all=-N -l". ``` -------------------------------- ### Mock Specific Interface Implementations with Selectors Source: https://github.com/bytedance/mockey/blob/main/README_cn.md Limit the scope of an interface method mock to specific implementation types using `SelectType` and `SelectPkg`. This allows for fine-grained control over which types are affected by the mock. Ensure the `exp/iface` package is imported. ```go package main import ( "bytes" "fmt" "io" . "github.com/bytedance/mockey/exp/iface" ) func main() { Mock(io.Reader.Read, SelectType("Reader"), SelectPkg("bytes")).Return(1, io.EOF).Build() // 只 mock bytes.Reader 类型的 Read 方法 reader1 := bytes.NewReader(nil) reader2 := bytes.NewBufferString("") fmt.Println(io.ReadAll(reader1)) // [0] , mock 生效 fmt.Println(io.ReadAll(reader2)) // [] , mock 不生效, 被选择器过滤 } ``` -------------------------------- ### Decorator Pattern with Origin and To Source: https://github.com/bytedance/mockey/blob/main/README_cn.md Use the `Origin` and `To` methods to apply a decorator pattern to a mocked function. `Origin` holds the original function's logic, and `To` defines the decorator function that wraps the original logic, allowing for AOP-like behavior. Ensure the `mockey` package is imported. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Foo(in string) string { return "ori:" + in } func main() { // `origin` 将携带 `Foo` 函数的逻辑 origin := Foo // `decorator` 将在 `origin` 周围做一些 AOP decorator := func(in string) string { fmt.Println("arg is", in) out := origin(in) fmt.Println("res is", out) return out } Mock(Foo).Origin(&origin).To(decorator).Build() fmt.Println(Foo("anything")) /* arg is anything res is ori:anything ori:anything */ } ``` -------------------------------- ### Conditional Mocking with Multiple When Clauses Source: https://github.com/bytedance/mockey/blob/main/README_cn.md Define multiple conditions for mocking a function using the `When` clause. Each `When` clause takes a function with the same signature as the original function to evaluate the condition. The first condition that evaluates to true will determine the mock's return value. Ensure the `mockey` package is imported. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Foo(in string) string { return "ori:" + in } func main() { // 注意:条件函数必须与原始函数具有相同的输入签名! Mock(Foo). When(func(in string) bool { return len(in) == 0 }).Return("EMPTY"). When(func(in string) bool { return len(in) <= 2 }).Return("SHORT"). When(func(in string) bool { return len(in) <= 5 }).Return("MEDIUM"). Build() fmt.Println(Foo("")) // EMPTY fmt.Println(Foo("h")) // SHORT fmt.Println(Foo("hello")) // MEDIUM fmt.Println(Foo("hello world")) // ori:hello world } ``` -------------------------------- ### Specify Mock Return Values in Go Source: https://context7.com/bytedance/mockey/llms.txt Use the Return method to define the values a mocked function should return. Ensure return values match the function's signature. Supports returning errors. ```go package main import ( "errors" "fmt" . "github.com/bytedance/mockey" ) func GetUser(id int) (string, error) { // Real implementation would fetch from database return "", errors.New("not implemented") } func main() { // Mock with single return value Mock(GetUser).Return("John Doe", nil).Build() name, err := GetUser(1) fmt.Println(name, err) // Output: John Doe // Mock with error return Mock(GetUser).Return("", errors.New("user not found")).Build() name, err = GetUser(999) fmt.Println(name, err) // Output: user not found } ``` -------------------------------- ### Mock Interface Method for All Implementations Source: https://github.com/bytedance/mockey/blob/main/README.md Mock a method for all types that implement a given interface. This is an experimental feature and the API may change. Use this when you need to affect all instances of an interface uniformly. ```go package main import ( "bytes" "fmt" "io" "net" "os" . "github.com/bytedance/mockey/exp/iface" ) func main() { // Mock the Read method of all Reader interface implementation types Mock(io.Reader.Read).Return(1, io.EOF).Build() reader1 := bytes.NewReader(nil) reader2 := bytes.NewBufferString("") reader3 := new(net.TCPConn) reader4 := new(os.File) fmt.Println(io.ReadAll(reader1)) // [0] , mocked fmt.Println(io.ReadAll(reader2)) // [0] , mocked fmt.Println(io.ReadAll(reader3)) // [0] , mocked fmt.Println(io.ReadAll(reader4)) // [0] , mocked } ``` -------------------------------- ### Origin - Call Original Function from Mock in Go Source: https://context7.com/bytedance/mockey/llms.txt The Origin method allows capturing the original function to call it from within a mock, enabling decorator-style patterns. This is useful for adding pre- or post-processing logic around the original function's execution. ```go package main import ( "fmt" "strings" . "github.com/bytedance/mockey" ) func ProcessRequest(input string) string { return "processed:" + input } func main() { // Capture original function for decorator pattern origin := ProcessRequest decorator := func(input string) string { fmt.Println("Before:", input) result := origin(input) // Call original fmt.Println("After:", result) return strings.ToUpper(result) } Mock(ProcessRequest).Origin(&origin).To(decorator).Build() result := ProcessRequest("test") // Output: // Before: test // After: processed:test fmt.Println("Final:", result) // Output: Final: PROCESSED:TEST } ``` -------------------------------- ### Implement decorator pattern with Origin in Go Source: https://github.com/bytedance/mockey/blob/main/README.md Use Origin to capture the original function logic, allowing for AOP-style wrapping around the target function. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Foo(in string) string { return "ori:" + in } func main() { // `origin` will carry the logic of the `Foo` function origin := Foo // `decorator` will do some AOP around `origin` decorator := func(in string) string { fmt.Println("arg is", in) out := origin(in) fmt.Println("res is", out) return out } Mock(Foo).Origin(&origin).To(decorator).Build() fmt.Println(Foo("anything")) /* arg is anything res is ori:anything ori:anything */ } ``` -------------------------------- ### Push changes to remote Source: https://github.com/bytedance/mockey/blob/main/CONTRIBUTING.md Upload the local feature branch to the remote repository. ```bash git push origin my-fix-branch ``` -------------------------------- ### Advanced Mocker Features: Tracking and Re-mocking Source: https://github.com/bytedance/mockey/blob/main/README_cn.md Obtain a `Mocker` object to access advanced features like tracking call counts (`Times`, `MockTimes`), re-mocking with new return values, and releasing the mock. Ensure the `mockey` package is imported. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Foo(in string) string { return in } func main() { mocker := Mock(Foo).When(func(in string) bool { return len(in) > 5 }).Return("MOCKED!").Build() fmt.Println(Foo("any")) // any fmt.Println(Foo("anything")) // MOCKED! // 使用 `MockTimes` 和 `Times` 跟踪 mock 工作次数和 `Foo` 被调用次数 fmt.Println(mocker.MockTimes()) // 1 fmt.Println(mocker.Times()) // 2 // 提示:重新mock或者释放mock时,相关的计数都会重置为0 // 重新 mock `Foo` 返回 "MOCKED2!" mocker.Return("MOCKED2!") fmt.Println(Foo("anything")) // MOCKED2! fmt.Println(mocker.MockTimes()) // 1 | 重新mock时被重置为0 // 释放 `Foo` mock mocker.Release() fmt.Println(Foo("anything")) // anything | mock 不起作用,因为 mock 已释放 fmt.Println(mocker.MockTimes()) // 0 | 释放时被重置为0 } ``` -------------------------------- ### Using PatchRun for Lightweight Mock Lifecycle Management Source: https://github.com/bytedance/mockey/blob/main/README.md Use PatchRun as a lightweight alternative when goconvey integration is not required. It ensures mocks are released immediately after the provided function block completes. ```go package main_test import ( "testing" . "github.com/bytedance/mockey" ) func Foo(in string) string { return "ori:" + in } func TestXXX(t *testing.T) { // mock PatchRun(func() { Mock(Foo).Return("MOCKED-1!").Build() // mock res := Foo("anything") // call if res != "MOCKED-1!" { t.Errorf("expected 'MOCKED-1!', got '%s'", res) } }) // mock released res := Foo("anything") // call if res != "ori:anything" { t.Errorf("expected 'ori:anything', got '%s'", res) } // mock again PatchRun(func() { Mock(Foo).Return("MOCKED-2!").Build() // mock res := Foo("anything") // call if res != "MOCKED-2!" { t.Errorf("expected 'MOCKED-2!', got '%s'", res) } }) // mock released res = Foo("anything") // call if res != "ori:anything" { t.Errorf("expected 'ori:anything', got '%s'", res) } } ``` -------------------------------- ### Mock Generic Functions and Methods Source: https://github.com/bytedance/mockey/blob/main/README.md Demonstrates using MockGeneric to intercept calls to generic functions and methods. Note that type mismatches will not be intercepted. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func FooGeneric[T any](t T) T { return t } type GenericClass[T any] struct { } func (g *GenericClass[T]) Foo(t T) T { return t } func main() { // mock generic function MockGeneric(FooGeneric[string]).Return("MOCKED!").Build() // `Mock(FooGeneric[string], OptGeneric)` also works fmt.Println(FooGeneric("anything")) // MOCKED! fmt.Println(FooGeneric(1)) // 1 | Not working because of type mismatch! // mock generic method MockGeneric((*GenericClass[string]).Foo).Return("MOCKED!").Build() fmt.Println(new(GenericClass[string]).Foo("anything")) // MOCKED! } ``` -------------------------------- ### Conditional Mocking in Go with Mockey Source: https://context7.com/bytedance/mockey/llms.txt Use the When method to define conditions for applying mocks. If a condition is false, the original function is called. Multiple When clauses can be chained. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Calculate(input int) string { return fmt.Sprintf("original:%d", input) } func main() { // Mock with multiple conditions Mock(Calculate). When(func(input int) bool { return input < 0 }).Return("NEGATIVE"). When(func(input int) bool { return input == 0 }).Return("ZERO"). When(func(input int) bool { return input <= 10 }).Return("SMALL"). Build() fmt.Println(Calculate(-5)) // Output: NEGATIVE fmt.Println(Calculate(0)) // Output: ZERO fmt.Println(Calculate(5)) // Output: SMALL fmt.Println(Calculate(100)) // Output: original:100 (no condition matched) } ``` -------------------------------- ### Avoid repeated mocking errors Source: https://github.com/bytedance/mockey/blob/main/README.md Demonstrates an invalid pattern where the same function is mocked multiple times, which will cause a panic. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Foo() string { return "" } func main() { Mock(Foo).Return("MOCKED!").Build() // mock for the first time Mock(Foo).Return("MOCKED2!").Build() // mock for the second time, will panic! fmt.Println(Foo()) } ``` -------------------------------- ### Mockey - When Conditional Mocking Source: https://context7.com/bytedance/mockey/llms.txt Details how to use the `When` method for conditional mocking. This allows specifying different mock behaviors based on input conditions, falling back to the original function if no condition is met. ```APIDOC ## When - Conditional Mocking ### Description The `When` method allows you to define conditions under which the mock should apply. If the condition returns false, the original function is called. ### Method `When` (on MockBuilder) ### Endpoint N/A (Function/Method Mocking) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Calculate(input int) string { return fmt.Sprintf("original:%d", input) } func main() { // Mock with multiple conditions Mock(Calculate). When(func(input int) bool { return input < 0 }).Return("NEGATIVE"). When(func(input int) bool { return input == 0 }).Return("ZERO"). When(func(input int) bool { return input <= 10 }).Return("SMALL"). Build() fmt.Println(Calculate(-5)) // Output: NEGATIVE fmt.Println(Calculate(0)) // Output: ZERO fmt.Println(Calculate(5)) // Output: SMALL fmt.Println(Calculate(100)) // Output: original:100 (no condition matched) } ``` ### Response #### Success Response (N/A) N/A #### Response Example N/A ``` -------------------------------- ### Mock Method Through Instance with GetMethod Source: https://github.com/bytedance/mockey/blob/main/README.md Use GetMethod to mock a method on an instance of a type. This is useful when direct mocking of the type's method is not possible. Ensure the instance is not nil. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) type A struct{} func (a A) Foo(in string) string { return in } func main() { a := new(A) // Mock(a.Foo) won't work, because `a` is an instance of `A`, not the type `A` // Tips: if the instance is an interface type, you can use it the same way // var ia interface{ Foo(string) string } = new(A) // Mock(GetMethod(ia, "Foo")).Return("MOCKED!").Build() Mock(GetMethod(a, "Foo")).Return("MOCKED!").Build() fmt.Println(a.Foo("anything")) // MOCKED! } ``` -------------------------------- ### MockValue - Mock Variables in Go Source: https://context7.com/bytedance/mockey/llms.txt MockValue allows mocking package-level or global variables by replacing their values. This is useful for testing code that relies on global configuration or state. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) var ( GlobalConfig = "production" MaxRetries = 3 EnableDebug = false ) func main() { // Mock string variable MockValue(&GlobalConfig).To("testing") fmt.Println(GlobalConfig) // Output: testing // Mock integer variable MockValue(&MaxRetries).To(10) fmt.Println(MaxRetries) // Output: 10 // Mock boolean variable MockValue(&EnableDebug).To(true) fmt.Println(EnableDebug) // Output: true } ``` -------------------------------- ### GetMethod - Mock Methods by Instance in Go Source: https://context7.com/bytedance/mockey/llms.txt Use GetMethod to mock methods by instance, which is particularly useful for mocking unexported types, unexported methods, or methods within nested structs. This allows mocking methods that might not be directly accessible via type definitions. ```go package main import ( "bytes" "crypto/sha256" "fmt" . "github.com/bytedance/mockey" ) type Wrapper struct { inner } type inner struct{} func (i inner) Process(in string) string { return "processed:" + in } func main() { // Mock method from instance (useful for interfaces) buf := bytes.NewBuffer([]byte{1, 2, 3}) Mock(GetMethod(buf, "Len")).Return(999).Build() fmt.Println(buf.Len()) // Output: 999 // Mock unexported type's method Mock(GetMethod(sha256.New(), "Sum")).Return([]byte{0, 1, 2}).Build() hash := sha256.New() fmt.Println(hash.Sum(nil)) // Output: [0 1 2] // Mock method in nested struct Mock(GetMethod(Wrapper{}, "Process")).Return("MOCKED").Build() fmt.Println(Wrapper{}.Process("test")) // Output: MOCKED } ``` -------------------------------- ### Mock Interface Method for Specific Implementations Source: https://github.com/bytedance/mockey/blob/main/README.md Limit interface method mocking to specific implementation types using SelectType and SelectPkg options. This allows for targeted mocking within an interface hierarchy. ```go package main import ( "bytes" "fmt" "io" . "github.com/bytedance/mockey/exp/iface" ) func main() { Mock(io.Reader.Read, SelectType("Reader"), SelectPkg("bytes")).Return(1, io.EOF).Build() // only mock the Read method of bytes.Reader type reader1 := bytes.NewReader(nil) reader2 := bytes.NewBufferString("") fmt.Println(io.ReadAll(reader1)) // [0] , mocked fmt.Println(io.ReadAll(reader2)) // [] , not mocked, filtered by selector } ``` -------------------------------- ### Avoid Mocking System Functions to Prevent Crashes Source: https://github.com/bytedance/mockey/blob/main/README_cn.md Directly mocking system functions, such as `time.Now`, can lead to probabilistic crashes like 'semacquire not on the G stack'. ```text fatal error: semacquire not on the G stack ``` -------------------------------- ### Mockey - To Custom Hook Function Source: https://context7.com/bytedance/mockey/llms.txt Illustrates using the `To` method to provide a custom hook function that replaces the original function's logic. The hook function must match the target function's signature. ```APIDOC ## To - Specify Custom Hook Function ### Description The `To` method allows you to provide a custom hook function that replaces the original function. The hook function must have the same signature as the target function. ### Method `To` (on MockBuilder) ### Endpoint N/A (Function/Method Mocking) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go package main import ( "fmt" "strings" . "github.com/bytedance/mockey" ) func ProcessData(input string) string { return input } type UserService struct { prefix string } func (u UserService) GetName(id int) string { return fmt.Sprintf("%s:user-%d", u.prefix, id) } func main() { // Mock function with custom logic Mock(ProcessData).To(func(input string) string { return strings.ToUpper(input) + "_MOCKED" }).Build() fmt.Println(ProcessData("hello")) // Output: HELLO_MOCKED // Mock method with receiver access in hook Mock(UserService.GetName).To(func(u UserService, id int) string { return fmt.Sprintf("MOCKED:%s:id=%d", u.prefix, id) }).Build() svc := UserService{prefix: "test"} fmt.Println(svc.GetName(123)) // Output: MOCKED:test:id=123 } ``` ### Response #### Success Response (N/A) N/A #### Response Example N/A ``` -------------------------------- ### Lightweight Mock Lifecycle with PatchRun Source: https://context7.com/bytedance/mockey/llms.txt PatchRun offers automatic mock cleanup without goconvey. Mocks are active only within the PatchRun function scope and are automatically released upon exit. ```go package main_test import ( "testing" . "github.com/bytedance/mockey" ) func Compute(x int) int { return x * 2 } func TestWithPatchRun(t *testing.T) { // Mock is active only within PatchRun PatchRun(func() { Mock(Compute).Return(100).Build() if Compute(5) != 100 { t.Error("expected 100") } }) // Mock automatically released if Compute(5) != 10 { t.Error("expected original behavior: 10") } // Nested PatchRun PatchRun(func() { Mock(Compute).Return(50).Build() PatchRun(func() { Mock(Compute).Return(25).Build() if Compute(5) != 25 { t.Error("expected 25 in inner scope") } }) // Inner mock released, outer mock still active if Compute(5) != 50 { t.Error("expected 50 in outer scope") } }) } ``` -------------------------------- ### Mocker API for Advanced Mock Control Source: https://context7.com/bytedance/mockey/llms.txt The Mocker struct, returned by Build(), allows dynamic modification of mock behavior, tracking usage, and releasing mocks. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Process(input string) string { return "processed:" + input } func main() { mocker := Mock(Process). When(func(input string) bool { return len(input) > 5 }). Return("LONG"). Build() Process("hi") // Not mocked (condition not met) Process("hello world") // Mocked Process("short") // Not mocked Process("longer text") // Mocked fmt.Println("Total calls:", mocker.Times()) // Output: Total calls: 4 fmt.Println("Mocked calls:", mocker.MockTimes()) // Output: Mocked calls: 2 // Dynamically change return value mocker.Return("CHANGED") fmt.Println(Process("long input")) // Output: CHANGED // Release and rebuild builder := mocker.Release() fmt.Println(Process("test")) // Output: processed:test (original behavior) builder.Return("NEW_MOCK").Build() fmt.Println(Process("test")) // Output: NEW_MOCK } ``` -------------------------------- ### Define conditional mocks in Go Source: https://github.com/bytedance/mockey/blob/main/README.md Use When to define multiple conditions for a mock. The condition function must match the input signature of the original function. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) func Foo(in string) string { return "ori:" + in } func main() { // NOTE: condition function must have the same input signature as the original function! Mock(Foo). When(func(in string) bool { return len(in) == 0 }).Return("EMPTY"). When(func(in string) bool { return len(in) <= 2 }).Return("SHORT"). When(func(in string) bool { return len(in) <= 5 }).Return("MEDIUM"). Build() fmt.Println(Foo("")) // EMPTY fmt.Println(Foo("h")) // SHORT fmt.Println(Foo("hello")) // MEDIUM fmt.Println(Foo("hello world")) // ori:hello world } ``` -------------------------------- ### Configure Compilation Flags Source: https://context7.com/bytedance/mockey/llms.txt Required compiler flags to disable inlining and optimization for Mockey to function correctly. ```bash # For tests go test -gcflags="all=-l -N" -v ./... # For building applications go build -gcflags="all=-l -N" ``` ```json { "go.buildFlags": ["-gcflags='all=-N -l'"] } ``` -------------------------------- ### Handle Goroutine Execution Timing with Mockey Source: https://github.com/bytedance/mockey/blob/main/README.md When mocking functions executed in other goroutines, be aware that the mock may be released before the function call. Use `PatchConvey` to manage the scope of mocks. ```go package main_test import ( "fmt" "testing" "time" . "github.com/bytedance/mockey" ) func Foo(in string) string { return in } func TestXXX(t *testing.T) { PatchConvey("TestXXX", t, func() { Mock(Foo).Return("MOCKED!").Build() go func() { fmt.Println(Foo("anything")) }() // the timing of executing 'Foo' is uncertain }) // when the main goroutine comes here, the relevant mock has been released by 'PatchConvey'. If 'Foo' is executed before this, the mock succeeds, otherwise it fails fmt.Println("over") time.Sleep(time.Second) } ``` -------------------------------- ### Handle Generic Type Interference Source: https://github.com/bytedance/mockey/blob/main/README.md Illustrates how mocking one type can interfere with others sharing the same underlying type in older Go versions. ```go package main import ( "fmt" . "github.com/bytedance/mockey" ) type MyString string func FooGeneric[T any](t T) T { return t } func main() { MockGeneric(FooGeneric[string]).Return("MOCKED!").Build() fmt.Println(FooGeneric("anything")) // MOCKED! fmt.Println(FooGeneric[MyString]("anything")) // MOCKED! | This is due to interference after mocking the string type } ```