如何模拟 *exec.Cmd / exec.Command()?

dou*_*k13 5 mocking go

我需要嘲笑exec.Command()

我可以使用以下方法来模拟它:

var rName string
var rArgs []string

mockExecCommand := func(name string, arg ...string) *exec.Cmd {
    rName = name
    rArgs = arg

    return nil
}
Run Code Online (Sandbox Code Playgroud)

然而,这在实际代码中不起作用,因为它抱怨 nil 指针,因为返回exec.Cmd调用Run().

我试着像这样嘲笑它:

type mock exec.Cmd

func (m *mock) Run() error {
    return nil
}

var rName string
var rArgs []string

mockExecCommand := func(name string, arg ...string) *exec.Cmd {
    rName = name
    rArgs = arg

    m := mock{}

    return &m
}
Run Code Online (Sandbox Code Playgroud)

但它抱怨:cannot use &m (value of type *mock) as *exec.Cmd value in return statementcompilerIncompatibleAssign

有什么办法可以解决这个问题吗?有更好的方法来嘲笑吗exec.Command()

如果我返回“模拟”命令,模拟函数就会起作用,尽管我Run()也更喜欢控制该函数:

var rName string
var rArgs []string

mockExecCommand := func(name string, arg ...string) *exec.Cmd {
    rName = name
    rArgs = arg

    return exec.Command("echo")
}
Run Code Online (Sandbox Code Playgroud)

dou*_*k13 3

实际上有一种方法可以做到这一点。所有功劳都归功于这篇文章。请查看以下内容的解释:

func fakeExecCommand(command string, args...string) *exec.Cmd {
    cs := []string{"-test.run=TestHelperProcess", "--", command}
    cs = append(cs, args...)
    cmd := exec.Command(os.Args[0], cs...)
    cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
    return cmd
}

func TestHelperProcess(t *testing.T){
    if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
        return
    }
    os.Exit(0)
}
Run Code Online (Sandbox Code Playgroud)