mockey

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2023 License: Apache-2.0 Imports: 7 Imported by: 0

README

Mockey

English | 中文

Mockey is a simple and easy-to-use golang mock library, which can quickly and conveniently mock functions and variables. At present, it is widely used in the unit test writing of ByteDance services. The bottom layer is monkey patch realized by rewriting function instructions at runtime.

  1. inlining and compilation optimization need to be disabled during compilation, otherwise mock may fail or an error may be reported. See the following FAQ chapter for details.
  2. In the actual process of writing a unit test, it is recommended to use it together with the Convey library.

Install

go get github.com/Sychorius/mockey@latest

Quick Guide

import (
	"fmt"
	"testing"

	. "github.com/Sychorius/mockey"
	. "github.com/smartystreets/goconvey/convey"
)

func Foo(in string) string {
	return in
}

type A struct{}

func (a A) Foo(in string) string { return in }

var Bar = 0

func TestMockXXX(t *testing.T) {
	PatchConvey("TestMockXXX", t, func() {
		Mock(Foo).Return("c").Build()   // mock function
		Mock(A.Foo).Return("c").Build() // mock method
		MockValue(&Bar).To(1)           // mock variable

		So(Foo("a"), ShouldEqual, "c")        // assert `Foo` is mocked
		So(new(A).Foo("b"), ShouldEqual, "c") // assert `A.Foo` is mocked
		So(Bar, ShouldEqual, 1)               // assert `Bar` is mocked
	})
	// mock is released automatically outside `PatchConvey`
	fmt.Println(Foo("a"))        // a
	fmt.Println(new(A).Foo("b")) // b
	fmt.Println(Bar)             // 0
}

Features

  • Mock functions and methods
    • Basic
      • Common / variant parameter function
      • Common / variant parameter method
      • Nested structure method
      • Export method of private type (under different packages)
    • Advanced
      • Execute the original function after mocking
      • Goroutine conditional filtering
      • Incrementally change mock behavior
      • Get the execution times of target function
      • Get the execution times of mock function
  • Mock variable
    • Common variable
    • Function variable

Compatibility

OS Support
  • Mac OS(Darwin)
  • Linux
  • Windows
Arch Support
  • AMD64
  • ARM64
Version Support
  • Go 1.13+

License

Mockey is distributed under the Apache License, version 2.0. The licenses of third party dependencies of Mockey are explained here.

FAQ

How to disable inline and compile optimization?
  1. Command line:go test -gcflags="all=-l -N" -v ./...
  2. Goland:fill -gcflags="all=-l -N" in the Run/Debug Configurations > Go tool arguments dialog box
The original function is still entered after mocking?
  1. Inline or compilation optimization is not disabled: you can try to use the debug mode. If you can run through it, it means that it is the problem. Please go to the relevant section of FAQ
  2. The Build() method was not called: forgot to call Build(), resulting in no actual effect
  3. Target function does not match exactly:
func TestXXX(t *testing.T) {
   Mock((*A).Foo).Return("c").Build()
   fmt.Println(A{}.Foo("a")) // enters the original function, because the mock target should be `A.Foo`

   a := A{}
   Mock(a.Foo).Return("c").Build()
   fmt.Println(a.Foo("a")) // enters the original function, because the mock target should be `A.Foo` or extracted from instance `a` using `GetMethod`
}
  1. The target function is executed in other goroutines:
func TestXXX(t *testing.T) {
   PatchConvey("TestXXX", t, func() {
      Mock(Foo).Return("c").Build()
      go Foo("a") // 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)
}
Error "function is too short to patch"?
  1. Inline or compilation optimization is not disabled: you can try to use the debug mode. If you can run through it, it means that it is the problem. Please go to the relevant section of FAQ
  2. The function is really too short: it means that the target function is less than one line, resulting in the compiled machine code being too short. Generally, two or more lines will not cause this problem
  3. Repeat mocking the same function: repeat mocking the same function in the PatchConvey of the smallest unit. If there is such a need, please get the Mocker instance and remock.
  4. Other tools mock this function: for example, monkey or other tools have mocked this function

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetGoroutineId

func GetGoroutineId() int64

GetGoroutineId ... Deprecated

func GetMethod

func GetMethod(instance interface{}, methodName string) interface{}

GetMethod resolve a certain public method from an instance.

func GetNestedMethod

func GetNestedMethod(instance interface{}, methodName string) interface{}

GetNestedMethod resolves a certain public method in anonymous structs, it will look for the specific method in every anonymous struct field recursively. Deprecated, use GetMethod instead.

func GetPrivateMethod

func GetPrivateMethod(instance interface{}, methodName string) interface{}

GetPrivateMethod ... Deprecated, use GetMethod instead.

func PatchConvey

func PatchConvey(items ...interface{})

func Sequence

func Sequence(value ...interface{}) sequenceOpt

Types

type FilterGoroutineType

type FilterGoroutineType int64
const (
	Disable FilterGoroutineType = 0
	Include FilterGoroutineType = 1
	Exclude FilterGoroutineType = 2
)

type MockBuilder

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

func Mock

func Mock(target interface{}) *MockBuilder

func MockUnsafe

func MockUnsafe(target interface{}) *MockBuilder

MockUnsafe has the full ability of the Mock function and removes some security restrictions. This is an alternative when the Mock function fails. It may cause some unknown problems, so we recommend using Mock under normal conditions.

func (*MockBuilder) Build

func (builder *MockBuilder) Build() *Mocker

func (*MockBuilder) ExcludeCurrentGoRoutine

func (builder *MockBuilder) ExcludeCurrentGoRoutine() *MockBuilder

func (*MockBuilder) FilterGoRoutine

func (builder *MockBuilder) FilterGoRoutine(filter FilterGoroutineType, gId int64) *MockBuilder

func (*MockBuilder) IncludeCurrentGoRoutine

func (builder *MockBuilder) IncludeCurrentGoRoutine() *MockBuilder

func (*MockBuilder) Origin

func (builder *MockBuilder) Origin(funcPtr interface{}) *MockBuilder

func (*MockBuilder) Return

func (builder *MockBuilder) Return(results ...interface{}) *MockBuilder

func (*MockBuilder) To

func (builder *MockBuilder) To(hook interface{}) *MockBuilder

To declares the hook function that's called to replace the target function.

The hook function must have the same signature as the target function.

The following example would make Fun always return true

func Fun(input string) bool {
	return input == "fun"
}

Mock(Fun).To(func(_ string) bool {return true}).Build()

Note that if the target function is a struct method, you may optionally include the receiver as the first argument of the hook function. For example,

type Foo struct {
	Name string
}
func (f *Foo) Bar(other string) bool {
	return other == f.Name
}
Mock((*Foo).Bar).To(func(f *Foo, other string) bool {return true}).Build()

func (*MockBuilder) When

func (builder *MockBuilder) When(when interface{}) *MockBuilder

When declares the condition hook that's called to determine whether the mock should be executed.

The condition hook function must have the same parameters as the target function.

The following example would execute the mock when input int is negative

func Fun(input int) string {
	return strconv.Itoa(input)
}
Mock(Fun).When(func(input int) bool { return input < 0 }).Return("0").Build()

Note that if the target function is a struct method, you may optionally include the receiver as the first argument of the condition hook function. For example,

type Foo struct {
	Age int
}
func (f *Foo) GetAge(younger int) string {
	return strconv.Itoa(f.Age - younger)
}
Mock((*Foo).GetAge).When(func(f *Foo, younger int) bool { return younger < 0 }).Return("0").Build()

type Mocker

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

func (*Mocker) ExcludeCurrentGoRoutine

func (mocker *Mocker) ExcludeCurrentGoRoutine() *Mocker

func (*Mocker) FilterGoRoutine

func (mocker *Mocker) FilterGoRoutine(filter FilterGoroutineType, gId int64) *Mocker

func (*Mocker) IncludeCurrentGoRoutine

func (mocker *Mocker) IncludeCurrentGoRoutine() *Mocker

func (*Mocker) MockTimes

func (mocker *Mocker) MockTimes() int

func (*Mocker) Origin

func (mocker *Mocker) Origin(funcPtr interface{}) *Mocker

func (*Mocker) Patch

func (mocker *Mocker) Patch() *Mocker

func (*Mocker) Release

func (mocker *Mocker) Release() *MockBuilder

func (*Mocker) Return

func (mocker *Mocker) Return(results ...interface{}) *Mocker

func (*Mocker) Times

func (mocker *Mocker) Times() int

func (*Mocker) To

func (mocker *Mocker) To(to interface{}) *Mocker

func (*Mocker) UnPatch

func (mocker *Mocker) UnPatch() *Mocker

func (*Mocker) When

func (mocker *Mocker) When(when interface{}) *Mocker

type MockerVar

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

func MockValue

func MockValue(targetPtr interface{}) *MockerVar

func (*MockerVar) Patch

func (mocker *MockerVar) Patch() *MockerVar

func (*MockerVar) To

func (mocker *MockerVar) To(value interface{}) *MockerVar

func (*MockerVar) UnPatch

func (mocker *MockerVar) UnPatch() *MockerVar

type MockeyPrivate

type MockeyPrivate struct{}

type Private

type Private interface {
	// contains filtered or unexported methods
}

type SequenceOpt

type SequenceOpt interface {
	// make sure it is mockey private interface
	Private
	// GetNext is used by mockey, don't use it if you don't know what it does
	GetNext() []interface{}
}

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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