Go-Spring :: Mock v0.0.1 发布,类型安全的 Go 语言 Mocking 库


mock 是一个现代化的、类型安全的 Go 语言 mocking 库,完全支持泛型编程。它提供了简单易用的接口, 可以帮助开发者轻松创建和管理模拟对象,从而提高单元测试的质量和效率。该库旨在解决 Go 语言中传统 mocking 工具存在的类型安全性不足和使用复杂性问题。

主要特性

  • 类型安全:利用 Go 1.18+ 的泛型特性,确保编译时的安全性,避免运行时类型错误
  • 多种 Mock 模式
    • Handle 模式:直接处理函数调用
    • When/Return 模式:基于条件的模拟返回
  • 灵活的方法匹配:支持不同数量和类型的参数及返回值(最多支持5个参数和5个返回值)
  • 上下文支持:提供与 context 包的集成,方便在分布式系统中进行测试
  • 自动重置功能:Manager 提供 Reset 方法,可轻松重置所有模拟器到初始状态
  • 详细的错误信息:当没有匹配的 mock 代码或存在多个匹配时,提供清晰的错误提示

安装工具

gsmock 是一个用于生成 Go mock 代码的工具,你可以通过以下方式安装它:

go install github.com/go-spring/mock/gsmock@latest

基本用法

  1. 定义接口

首先,在你的项目中定义需要 mock 的接口。例如,创建一个名为 service.go 的文件,并添加如下代码:

package main

type Service interface {
	Save(r1, r2, r3, r4, r5, r6 int)
}
 
  1. 生成 Mock 代码

然后在 service.go 文件中加入 go:generate 指令,即可生成 mock 代码:

//go:generate gsmock
 

你需要指定一个输出文件名,例如 service_mock.go,否则会输出到控制台上。

//go:generate gsmock -o src_mock.go
 

你还可以指定哪些接口生成 mock,哪些接口不生成 mock (在接口名前面加!即可)。

//go:generate gsmock -o src_mock.go -i '!RepositoryV2,Repository'
 

使用示例

以下是一个简单的使用示例:

package mock_test

import (
	"context"
	"reflect"
	"testing"

	"github.com/go-spring/mock"
	"github.com/go-spring/mock/internal/assert"
)

type Trace struct {
	TraceId string
}

type Request struct {
	Token string
}

type Response struct {
	Message string
}

type Client struct{}

var clientType = reflect.TypeFor[Client]()

func (c *Client) Get(ctx context.Context, req *Request, trace *Trace) (*Response, error) {
	if ret, ok := mock.InvokeContext(ctx, clientType, "Get", ctx, req, trace); ok {
		return mock.Unbox2[*Response, error](ret)
	}
	return &Response{Message: "9:xxx"}, nil
}

// MockGet registers a mock implementation for the Get method.
func MockGet(r *mock.Manager) *mock.Mocker32[context.Context, *Request, *Trace, *Response, error] {
	return mock.NewMocker32[context.Context, *Request, *Trace, *Response, error](r, clientType, "Get")
}

func TestMockWithContext(t *testing.T) {
	var c Client

	// Test case: Unmocked
	{
		resp, err := c.Get(t.Context(), &Request{}, &Trace{})
		assert.Nil(t, err)
		assert.Equal(t, resp.Message, "9:xxx")
	}

	r := mock.NewManager()
	ctx := r.BindTo(t.Context())

	// Test case: When && Return
	{
		r.Reset()
		MockGet(r).
			When(func(ctx context.Context, req *Request, trace *Trace) bool {
				return req.Token == "1:abc"
			}).
			Return(func() (resp *Response, err error) {
				return &Response{Message: "1:abc"}, nil
			})

		resp, err := c.Get(ctx, &Request{Token: "1:abc"}, &Trace{})
		assert.Nil(t, err)
		assert.Equal(t, resp.Message, "1:abc")
	}

	// Test case: Handle
	{
		r.Reset()
		MockGet(r).
			Handle(func(ctx context.Context, req *Request, trace *Trace) (resp *Response, err error) {
				return &Response{Message: "4:xyz"}, nil
			})

		resp, err := c.Get(ctx, &Request{Token: "4:xyz"}, &Trace{})
		assert.Nil(t, err)
		assert.Equal(t, resp.Message, "4:xyz")
	}

	// Test case: Invalid Handle
	{
		r.Reset()
		MockGet(r).Handle(nil)

		resp, err := c.Get(ctx, &Request{}, &Trace{})
		assert.Nil(t, err)
		assert.Equal(t, resp.Message, "9:xxx")
	}
}

type ClientInterface interface {
	Query(req *Request, trace *Trace) (*Response, error)
}

// MockClient is a mock implementation of ClientInterface.
type MockClient struct {
	r *mock.Manager
}

var mockClientType = reflect.TypeFor[MockClient]()

// NewMockClient creates a new instance of MockClient.
func NewMockClient(r *mock.Manager) *MockClient {
	return &MockClient{r}
}

// Query mocks the Query method by invoking a registered mock implementation.
func (c *MockClient) Query(req *Request, trace *Trace) (*Response, error) {
	if ret, ok := mock.Invoke(c.r, mockClientType, "Query", req, trace); ok {
		return mock.Unbox2[*Response, error](ret)
	}
	panic("mock error")
}

// MockQuery registers a mock implementation for the Query method.
func (c *MockClient) MockQuery() *mock.Mocker22[*Request, *Trace, *Response, error] {
	return mock.NewMocker22[*Request, *Trace, *Response, error](c.r, mockClientType, "Query")
}

func TestMockNoContext(t *testing.T) {
	r := mock.NewManager()

	var c ClientInterface
	mc := NewMockClient(r)
	c = mc

	// Test case: When && Return
	{
		r.Reset()
		mc.MockQuery().
			When(func(req *Request, trace *Trace) bool {
				return req.Token == "1:abc"
			}).
			Return(func() (resp *Response, err error) {
				return &Response{Message: "1:abc"}, nil
			})

		resp, err := c.Query(&Request{Token: "1:abc"}, &Trace{})
		assert.Nil(t, err)
		assert.Equal(t, resp.Message, "1:abc")
	}

	// Test case: Handle
	{
		r.Reset()
		mc.MockQuery().
			Handle(func(req *Request, trace *Trace) (resp *Response, err error) {
				return &Response{Message: "4:xyz"}, nil
			})

		resp, err := c.Query(&Request{Token: "4:xyz"}, &Trace{})
		assert.Nil(t, err)
		assert.Equal(t, resp.Message, "4:xyz")
	}

	// Test case: Invalid Handle
	{
		r.Reset()
		mc.MockQuery().Handle(nil)

		assert.Panic(t, func() {
			_, _ = c.Query(&Request{}, &Trace{})
		}, "mock error")
	}
}

相關推薦

2025-06-15

Go-Spring :: Log 是一个高性能、可扩展的日志处理库,专为 Go 语言设计。它提供了灵活的日志记录功能,支持结构化日志、 上下文字段提取、多级日志配置以及多种输出方式,适用于各种服务端应用场景。 特性 多级日志支持

2025-05-03

🎉 很高兴宣布 Go-Spring 全新版本正式发布! 这是一个融合了 Java Spring 生态成熟理念 🌱 与 Go 语言高性能特性 ⚡ 的现代框架, 旨在为 Go 开发者 👨 💻👩 💻 提供更高效、更优雅的应用开发体验 ✨。 🌟 框架简介 Go-Spring 是

2022-09-14

距离上次发版仅两周的时间,Go 后端一站式开发框架 Go-Spring 又发布了新的版本,新版本实现了两个非常重要的特性:动态配置和 Bean 共享。 动态配置 有时候我们想要在不停机的情况下可以修改程序的配置,更改程序的行为,

2022-11-16

: Notable changes 支持 Node.js 测试运行器上的 function mocking #45326 node:test 模块在测试过程中通过顶层的 mock object 支持 mocking。 test('spies on an object method', (t) => { const number = { value: 5, add(a) { return this.value + a; }, }; t.mock.method

2023-04-18

CL 团队很高兴地宣布 KCL v0.4.6 新版本现在已经可用!本次发布为大家带来了三方面的重点更新:语言、工具链、社区集成 & 扩展支持。 使用 IDE 插件提升 KCL 代码编写体验和效率 Helm/Kustomize/KPT 云原生社区工具集成 完善 KC

2024-08-22

Simple Admin - Go 语言分布式后台管理系统 v1.5.4 更新 项目介绍 Simple Admin 是一个开箱即用的分布式微服务后端管理系统,基于 go-zero 开发,为开发小型到大型项目后台提供了丰富的功能,易于扩展,支持三端代码生成。 官方自带

2025-06-21

言,支持函数式、命令式和面向对象等多种范式,包括值类型、类和接口、泛型、代数数据类型、模式匹配、以及高阶函数等特性。此外,仓颉还支持类型推断,能够减轻开发者类型标注的负担;通过一系列简明高效的语法,能

2024-06-22

言,支持函数式、命令式和面向对象等多种范式,包括值类型、类和接口、泛型、代数数据类型、模式匹配、以及高阶函数等特性。此外,仓颉还支持类型推断,能够降低开发者类型标注的负担;通过一系列简明高效的语法,能

2024-07-30

Simple Admin - Go 语言分布式后台管理系统 v1.5.2 更新 项目介绍 Simple Admin 是一个开箱即用的分布式微服务后端管理系统,基于 go-zero 开发,为开发小型到大型项目后台提供了丰富的功能,易于扩展,支持三端代码生成。 官方自带

2024-07-16

Simple Admin - Go 语言分布式后台管理系统 v1.5.0 更新 项目介绍 Simple Admin 是一个开箱即用的分布式微服务后端管理系统,基于 go-zero 开发,为开发小型到大型项目后台提供了丰富的功能,易于扩展,支持三端代码生成。 官方自带

2024-06-26

Simple Admin - Go 语言分布式后台管理系统 v1.4.8 更新 项目介绍 Simple Admin 是一个开箱即用的分布式微服务后端管理系统,基于 go-zero 开发,为开发小型到大型项目后台提供了丰富的功能,易于扩展,支持三端代码生成。 官方自带

2025-06-14

升性能、优化开发者体验以及增强云原生就绪能力。此次发布在工具链、运行时、编译器和标准库等多个方面引入了一系列增强功能,旨在使 Go 应用程序更快、更高效,并更易于开发和部署,尤其是在容器化环境中。它还凸显

2023-05-24

许可以使开发操作系统等复杂软件变得更加容易。例如,类型安全、错误处理和并发性在开发操作系统时应该是有益的。 因此,采用像 Go 这样的高级语言来开发操作系统理应是自然选择,但为什么并没有成功的案例? 操作

2022-03-01

于分配任意数量的 arena,可以从 arena 的内存中分配任意类型的对象,并且 arena 会根据需要自动增长大小。当一个 arena 中的所有对象不再使用时,可以显式释放该 arena 以有效地回收其内存,而无需进行常见的垃圾回收操作。我