简单说下最近遇到因为go函数内联导致的单测mock问题:
假设我们现在有这样一个简单的求max函数:
func max(a, b int) int {
if a > b {
return a
}
return b
}
然后我们使用gomonkey来mock掉这个函数(当然,这是为了演示,事实上我们mock掉的一般是rpc调用):
// TestMax
func TestMax(t *testing.T) {
// mock掉max方法
maxMock := ApplyFunc(max, func(_, _ int) int {
return 1
})
defer maxMock.Reset()
// assert
Convey("testMax", t, func() {
res := max(1, 2)
So(res, ShouldEqual, 1)
})
}
按照预期,我们将max()函数mock成永远返回1,这个单测是可以pass的。
然而它永远都跑不过,因为这里的max会返回2

这就引入今天要讨论的问题:内联
首先来说:
内联是什么?
内联就是把简短的函数在调用它的地方展开。在计算机发展历程的早期,这个优化是由程序员手动实现的。现在,内联已经成为编译过程中自动实现的基本优化过程的其中一步。
为什么编译过程会引入内联?
内联是高性能编程的一种重要手段。每个函数调用都有开销:创建栈帧,读写寄存器,这些开销可以通过内联避免。
我们使用命令
go run -gcflags="-m -m" main.go
来查看刚才的函数,确认是否被内联

可以看到,Max函数确实是被展开了。
所以我们刚才在调用前mock掉的单测,是没办法生效的。原因是,后面的被测代码压根没有调用Max函数。。。
那么:
如何禁用内联?
编译时加上参数:
-gcflags=all=-l
所以我们这样执行刚才的单测,可以看到pass了~
