單測代碼
func TestLogin(t *testing.T) {
// 初始化 dao 層
userDao := &daoUser.UserDao{}
// 初始化 service 層
entity := &LoginService{}
Convey("GetUserByUsername", t, func() {
Convey("Should be success", func() {
// 給 GetByUsername 函數打樁,指定返回值
patches := ApplyMethod(reflect.TypeOf(UserDao), "GetByUsername",
func(*daoUser.UserDao, string) (*daoUser.User, error) {
return &daoUser.User{
ID: 1,
Username: "weirwei",
Password: "123456",
}, nil
})
defer patches.Reset()
// 測試 Login
res, err := entity.Login("weirwei", "123456")
// 斷言
So(err, ShouldBeNil)
So(res, ShouldBeTrue)
})
})
}
問題分析
查看run
和debug
的命令
# run
/usr/local/go/bin/go test -c -o /private/var/folders/1q/llslx_n95d1brs7hq2drxjjw0000gn/T/___1go_test_gin_study_service_svUser gin-study/service/svUser
# debug
/usr/local/go/bin/go test -c -o /private/var/folders/1q/llslx_n95d1brs7hq2drxjjw0000gn/T/___go_test_gin_study_service_svUser -gcflags all=-N -l gin-study/service/svUser
很明顯就能發現debug
比run
多了 -gcflags all=-N -l
,這個就是禁用內聯的選項
內聯(inlining):粗暴的來說,就是將函數內容復制到函數調用的地方,減少了函數調用的開支,但一定程度上會增加程序的代碼量,占用更多的內存。
這么看就很明顯了,本來打樁后 GetUserByUsername
會直接返回給定的結果,不走 dao 層的實際代碼,但是 go 在編譯過程中會進行內聯優化,將 dao 層的代碼直接“復制”過來,繞過了測試樁。而在本段測試代碼中並沒有對 dao 層進行相關配置及初始化,導致代碼在執行時出現錯誤。