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

How to mock *exec.Cmd / exec.Command()?

我需要模拟 exec.Command()

我可以使用以下方式模拟它:

var rName string
var rArgs []string

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

    return nil
}

然而,这在实际代码中不起作用,因为它抱怨 nil 指针,因为 returning 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
}

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

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

如果我 return 一个“模拟”命令,模拟函数就可以工作,尽管我更愿意也控制 Run() 函数:

var rName string
var rArgs []string

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

    return exec.Command("echo")
}

How to mock *exec.Cmd / exec.Command()?

你不能。想出一个非 mock-based 测试策略。

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

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)
}