简介
xgo是一个使用纯go实现的单元测试框架,集成了Mock, Trace, Trap等功能。
xgo的项目地址: https://github.com/xhd2015/xgo
使用步骤
- 首先安装xgo
go install github.com/xhd2015/xgo/cmd/xgo@latest
- 创建一个demo工程
mkdir demo
cd demo
go mod init demo
- 将下面的内容添加到文件
demo_test.go
中:
package demo
import (
"testing"
"github.com/xhd2015/xgo/runtime/mock"
)
func greet(s string) string {
return "hello " + s
}
func TestPatchFunc(t *testing.T) {
mock.Patch(greet, func(s string) string {
return "mock " + s
})
res := greet("world")
if res != "mock world" {
t.Fatalf("expect patched result to be %q, actual: %q", "mock world", res)
}
}
- 获取依赖
go get github.com/xhd2015/xgo/runtime
- 执行单测
xgo test -v ./
输出:
=== RUN TestFuncMock
--- PASS: TestFuncMock (0.00s)
PASS
ok demo
如果使用go运行上面的代码, 它会失败:
go test -v ./
输出:
WARNING: failed to link __xgo_link_on_init_finished(requires xgo).
WARNING: failed to link __xgo_link_on_goexit(requires xgo).
=== RUN TestFuncMock
WARNING: failed to link __xgo_link_set_trap(requires xgo).
WARNING: failed to link __xgo_link_init_finished(requires xgo).
demo_test.go:21: expect MyFunc() to be 'mock func', actual: my func
--- FAIL: TestFuncMock (0.00s)
FAIL
FAIL demo 0.771s
FAIL
这是因为要实现Mock功能,需要使用xgo作为-toolexec的参数,具体原理参见文章xgo: golang基于-toolexec实现猴子补丁
Mock的使用概览
包github.com/xhd2015/xgo/runtime/mock
提供了以下2个主要的API,它们的功能相同,入参有所区别:
Patch(fn,replacer)
- 第二个参数replacer是一个函数,用来替换第一个函数fnMock(fn, interceptor)
- 第二个参数interceptor是一个拦截器,用来拦截第一个函数fn
它们可用于不同的场景,当你只需要简单替换时,使用Patch
, 当你需要实现通用的拦截器时,使用Mock
.
Mock的例子:
package demo
import (
"context"
"testing"
"github.com/xhd2015/xgo/runtime/core"
"github.com/xhd2015/xgo/runtime/mock"
)
func MyFunc() string {
return "my func"
}
func TestMock(t *testing.T) {
mock.Mock(MyFunc, func(ctx context.Context, fn *core.FuncInfo, args core.Object, results core.Object) error {
results.GetFieldIndex(0).Set("mock func")
return nil
})
text := MyFunc()
if text != "mock func" {
t.Fatalf("expect MyFunc() to be 'mock func', actual: %s", text)
}
}
Patch
的例子:
package demo
import (
"context"
"testing"
"github.com/xhd2015/xgo/runtime/core"
"github.com/xhd2015/xgo/runtime/mock"
)
func MyFunc() string {
return "my func"
}
func TestPatch(t *testing.T) {
mock.Patch(MyFunc, func() string {
return "mock func"
})
text := MyFunc()
if text != "mock func" {
t.Fatalf("expect MyFunc() to be 'mock func', actual: %s", text)
}
}