agiledragon / gomonkey

gomonkey is a library to make monkey patching in unit tests easy
MIT License
1.96k stars 179 forks source link

1.10以后禁用内联命令 #4

Closed fmnisme closed 5 years ago

fmnisme commented 5 years ago

应该换成: -gcflags "all=-N -l"

agiledragon commented 5 years ago

应该换成: -gcflags "all=-N -l"

我本地是 go1.11 版本,测试结果是 -gcflags=-l 生效啊

fmnisme commented 5 years ago

我是g1.10, 这段代码就不行

-i -v -gcflags=-l

b/b.go:

package b

func F2() string {
    return "F2"
}

func F() string {
    return F2()
}

main.go

import (
    "b"
    "fmt"
    "github.com/agiledragon/gomonkey"
)
func main() {
    gomonkey.ApplyFunc(b.F2, func() string {
        return "patched"
    })
    fmt.Printf("%v\n", b.F())
}
agiledragon commented 5 years ago

我是go1.11,上述情况-gcflags=-l的确不生效。我之前是在测试代码中验证的,同时我们只在测试代码中使用 gomonkey 了,于是问题来了,为啥-gcflags=-l在go test中生效? 示例代码:

func gg() int {
    return mm()
}
func mm() int {
    return 1
}

func TestMMApplyFunc(t *testing.T) {
    Convey("TestMMApplyFunc", t, func() {

        Convey("inline", func() {
            patches := ApplyFunc(mm, func() int {
                return 2
            })
            defer patches.Reset()
            i := gg()
            So(i, ShouldEqual, 2)
        })
    })
}

运行结果:

$ go version
go version go1.11 darwin/amd64

$ go test -gcflags=-l apply_func_test.go 
ok      command-line-arguments  (cached)

$ go test -gcflags "all=-N -l" apply_func_test.go 
ok      command-line-arguments  (cached)
zhaolitc commented 5 years ago

我简单修改了@fmnisme main.go的代码:


package main

import (
    "fmt"

    "github.com/agiledragon/gomonkey"
    "zte.com.cn/knitter/gomon/b"
)

func G2() string {
    return "G2"
}

func G() string {
    return G2()
}

func main() {
    gomonkey.ApplyFunc(b.F2, func() string {
        return "patchedF2"
    })

    gomonkey.ApplyFunc(G2, func() string {
        return "patchedG2"
    })

    fmt.Printf("b.F: %v\n", b.F())

    fmt.Printf("main.G: %v\n", G())
}

结果是:

[root@LIN-98C5F567B8E gomon]# go version
go version go1.11.1 linux/amd64

[root@LIN-98C5F567B8E gomon]# go run main.go 
b.F: F2
main.G: G2
[root@LIN-98C5F567B8E gomon]# go run -gcflags "-N -l" main.go 
b.F: F2
main.G: patchedG2
[root@LIN-98C5F567B8E gomon]# go run -gcflags "all=-N -l" main.go 
b.F: patchedF2
main.G: patchedG2
[root@LIN-98C5F567B8E gomon]# go run -gcflags "all=-l" main.go 
b.F: patchedF2
main.G: patchedG2

在结合golang对“all”的说明:

go help packages
.....
- "all" expands to all packages found in all the GOPATH
trees. For example, 'go list all' lists all the packages on the local
system. When using modules, "all" expands to all packages in
the main module and their dependencies, including dependencies
needed by tests of any of those.
......

我认为问题在于,F2函数在main之外的b包里,G2函数在main包内,这样仅使用“-N -l”时,golang编译器默认只对当前的顶层main包使用“-N -l”参数,而使用“all=-N -l”时,对b包也使用了“-N -l”参数,从而使对b包内的F函数禁用内联功能发挥出来。

zhaolitc commented 5 years ago

@agiledragon 我改了测试代码: b.go

package b

func F2() string {
    return "F2"
}

func F() string {
    return F2()
}

func GG() int {
    return MM()
}
func MM() int {
    return 1
}

main_test.go


package main

import (
    "testing"

    . "github.com/agiledragon/gomonkey"
    "github.com/smartystreets/goconvey/convey"
    "zte.com.cn/knitter/gomon/b"
)

func gg() int {
    return mm()
}
func mm() int {
    return 1
}

func TestMMApplyFunc(t *testing.T) {
    convey.Convey("TestMMApplyFunc", t, func() {

        convey.Convey("inline", func() {
            patches := ApplyFunc(mm, func() int {
                return 2
            })
            defer patches.Reset()
            i := gg()
            convey.So(i, convey.ShouldEqual, 2)
        })

        convey.Convey("inter packages inline", func() {
            patches := ApplyFunc(b.MM, func() int {
                return 2
            })
            defer patches.Reset()
            i := b.GG()
            convey.So(i, convey.ShouldEqual, 2)
        })
    })
}
[root@LIN-98C5F567B8E gomon]# go version
go version go1.11.1 linux/amd64

[root@LIN-98C5F567B8E gomon]# go test
xx
Failures:

  * /media/B/code/paasnw/src/zte.com.cn/knitter/gomon/gomon_test.go 
  Line 27:
  Expected: '2'
  Actual:   '1'
  (Should be equal)

  * /media/B/code/paasnw/src/zte.com.cn/knitter/gomon/gomon_test.go 
  Line 36:
  Expected: '2'
  Actual:   '1'
  (Should be equal)

2 total assertions

--- FAIL: TestMMApplyFunc (0.00s)
FAIL
exit status 1
FAIL    zte.com.cn/knitter/gomon    0.002s
[root@LIN-98C5F567B8E gomon]# go test -gcflags "all=-N -l"
..
2 total assertions

PASS
ok      zte.com.cn/knitter/gomon    0.002s
[root@LIN-98C5F567B8E gomon]# go test -gcflags "all=-l"
..
2 total assertions

PASS
ok      zte.com.cn/knitter/gomon    0.002s
[root@LIN-98C5F567B8E gomon]# go test -gcflags "-l"
.x
Failures:

  * /media/B/code/paasnw/src/zte.com.cn/knitter/gomon/gomon_test.go 
  Line 36:
  Expected: '2'
  Actual:   '1'
  (Should be equal)

2 total assertions

--- FAIL: TestMMApplyFunc (0.00s)
FAIL
exit status 1
FAIL    zte.com.cn/knitter/gomon    0.002s

验证了我在上面对非测试的业务代码中做的判断,当跨包打桩时需要添加all参数。

agiledragon commented 5 years ago

go版本升级不考虑向前兼容,不符合里氏替换原则,前段时间有反射机制,这几天又有内联禁用。 go1.10之前内联禁用命令:-gcflags=-l go1.10及之后内联禁用命令:-gcflags=all=-l