uber-go/mock
GitHub: uber-go/mock
Uber 维护的 Go 语言 mocking 框架,通过 mockgen 自动从接口生成 mock 代码以简化单元测试。
Stars: 3386 | Forks: 173
# gomock
[][ci-runs] [][reference]
gomock 是一个用于 [Go 编程语言][golang] 的 mocking 框架。它
与 Go 的内置 `testing` 包集成良好,但也可以在其他
环境中使用。
该项目起源于 Google 的 `golang/mock` 仓库。遗憾的是,Google
不再维护此项目,并且鉴于 gomock 在 Uber 内部的广泛使用,
我们决定 fork 该项目,并在 Uber 继续对其进行维护。
## 支持的 Go 版本
go.uber.org/mock 支持官方
[Go 发布策略](https://go.dev/doc/devel/release#policy) 所支持的所有 Go 版本。即,
Go 的两个最新发布版本。
## 安装
安装 `mockgen` 工具。
```
go install go.uber.org/mock/mockgen@latest
```
要确保其安装正确,请使用:
```
mockgen -version
```
如果失败,请确保您的 GOPATH/bin 已包含在 PATH 中。您可以通过以下命令添加:
```
export PATH=$PATH:$(go env GOPATH)/bin
```
## 运行 mockgen
`mockgen` 有三种操作模式:archive、source 和 package。
### Archive 模式
Archive 模式从一个包归档
文件 (.a) 生成 mock 接口。通过使用 -archive 标志来启用。应提供一个导入
路径和一个以逗号分隔的符号列表,作为该命令的非标志参数。
示例:
```
# 将 package 构建为 archive。
go build -o pkg.a database/sql/driver
mockgen -archive=pkg.a database/sql/driver Conn,Driver
```
### Source 模式
Source 模式从一个源文件生成 mock 接口。
通过使用 -source 标志来启用。在此模式下,其他可能
有用的标志包括 -imports 和 -aux_files。
示例:
```
mockgen -source=foo.go [other options]
```
### Package 模式
Package 模式通过指定包名和接口名来工作。
通过传递两个非标志参数来启用:一个导入路径,以及一个
以逗号分隔的符号列表。
您可以使用 "." 来引用当前路径的包。
示例:
```
mockgen database/sql/driver Conn,Driver
# 便于在 `go:generate` 中使用。
mockgen . Conn,Driver
```
### 标志
`mockgen` 命令用于在给定一个包含需要 mock 的接口的 Go 源文件的情况下,
为 mock 类生成源代码。
它支持以下标志:
- `-archive`:一个包含需要 mock 的接口的包归档文件。
- `-source`:一个包含需要 mock 的接口的文件。
- `-destination`:用于写入生成的源代码的文件。如果您
没有设置此项,代码将打印到标准输出。
- `-package`:用于生成的 mock 类
源代码的包。如果您没有设置此项,包名将为 `mock_` 并
拼接上输入文件的包名。
- `-imports`:在生成的
源代码中应使用的显式导入列表,指定为以逗号分隔的元素列表,
格式为 `foo=bar/baz`,其中 `bar/baz` 是被导入的包,而 `foo` 是
在生成的源代码中用于该包的标识符。
- `-aux_files`:为了解析(例如,定义在不同文件中的嵌入接口)而需要参考的
附加文件列表。这
指定为以逗号分隔的元素列表,格式为
`foo=bar/baz.go`,其中 `bar/baz.go` 是源文件,而 `foo` 是
-source 文件所使用的该文件的包名。
- `-build_flags`:(仅限 package 模式)原样传递给 `go list` 的标志。
- `-mock_names`:生成的 mock 的自定义名称列表。这
指定为以逗号分隔的元素列表,格式为
`Repository=MockSensorRepository,Endpoint=MockSensorEndpoint`,其中
`Repository` 是接口名,而 `MockSensorRepository` 是所需的
mock 名称(mock 工厂方法和 mock 记录器将以该 mock 命名)。
如果其中一个接口没有指定自定义名称,则将使用默认的命名
约定。
- `-self_package`:生成代码的完整包导入路径。此
标志的目的是防止在生成代码时,因尝试包含其自身的包而导致
导入循环。这种情况可能发生在 mock 的包
被设置为其输入之一(通常是主要的那个)且输出为 stdio 时,因此
mockgen 无法检测到最终的输出包。设置此标志将
告诉 mockgen 要排除哪个导入。
- `-copyright_file`:用于向生成的源代码添加版权头的版权文件。
- `-debug_parser`:仅打印解析器结果。
- `-write_package_comment`:如果为 true,则写入包文档注释 (godoc)。(默认为 true)
- `-write_generate_directive`:添加 //go:generate 指令以重新生成 mock。(默认为 false)
- `-write_source_comment`:如果为 true,则写入原始文件(source 模式)或接口名(package 模式)注释。(默认为 true)
- `-typed`:生成类型安全的 'Return'、'Do'、'DoAndReturn' 函数。(默认为 false)
- `-exclude_interfaces`:要排除的接口名称,以逗号分隔
有关 `mockgen` 用法的示例,请参见 `sample/` 目录。在简单的
情况下,您将只需要 `-source` 标志。
## 构建 Mock
```
type Foo interface {
Bar(x int) int
}
func SUT(f Foo) {
// ...
}
```
```
func TestFoo(t *testing.T) {
ctrl := gomock.NewController(t)
m := NewMockFoo(ctrl)
// Asserts that the first and only call to Bar() is passed 99.
// Anything else will fail.
m.
EXPECT().
Bar(gomock.Eq(99)).
Return(101)
SUT(m)
}
```
## 构建 Stub
```
type Foo interface {
Bar(x int) int
}
func SUT(f Foo) {
// ...
}
```
```
func TestFoo(t *testing.T) {
ctrl := gomock.NewController(t)
m := NewMockFoo(ctrl)
// Does not make any assertions. Executes the anonymous functions and returns
// its result when Bar is invoked with 99.
m.
EXPECT().
Bar(gomock.Eq(99)).
DoAndReturn(func(_ int) int {
time.Sleep(1*time.Second)
return 101
}).
AnyTimes()
// Does not make any assertions. Returns 103 when Bar is invoked with 101.
m.
EXPECT().
Bar(gomock.Eq(101)).
Return(103).
AnyTimes()
SUT(m)
}
```
## 修改失败信息
当 matcher 报告失败时,它会打印接收到的(`Got`)和
预期的(`Want`)值。
```
Got: [3]
Want: is equal to 2
Expected call at user_test.go:33 doesn't match the argument at index 1.
Got: [0 1 1 2 3]
Want: is equal to 1
```
### 修改 `Want`
`Want` 值来自 matcher 的 `String()` 方法。如果 matcher 的
默认输出不能满足您的需求,可以按如下方式进行修改:
```
gomock.WantFormatter(
gomock.StringerFunc(func() string { return "is equal to fifteen" }),
gomock.Eq(15),
)
```
这会将 `gomock.Eq(15)` matcher 针对于 `Want:` 的输出从 `is equal
to 15` 修改为 `is equal to fifteen`。
### 修改 `Got`
`Got` 值来自对象的 `String()` 方法(如果可用)。
在某些情况下,对象的输出难以阅读(例如,`[]byte`),
如果测试能以不同的方式打印它会很有帮助。以下内容
修改了 `Got` 值的格式化方式:
```
gomock.GotFormatterAdapter(
gomock.GotFormatterFunc(func(i any) string {
// Leading 0s
return fmt.Sprintf("%02d", i)
}),
gomock.Eq(15),
)
```
如果接收到的值为 `3`,那么它将被打印为 `03`。
标签:EVTX分析, Go, Mock框架, Ruby工具, SOC Prime, 代码生成, 单元测试, 开发工具, 日志审计, 测试工具, 渗透测试工具