我需要嘲笑exec.Command()。
我可以通过以下方式来模仿它:
var rName string
var rArgs []string
mockExecCommand := func(name string, arg ...string) *exec.Cmd {
rName = name
rArgs = arg
return 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
}但它抱怨道: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")
}发布于 2022-02-17 22:22:42
其实有办法做到这一点。所有的功劳都归于这的文章。看看下面是怎么回事的解释:
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)
}发布于 2022-09-28 00:28:43
当劫持测试可执行文件以运行特定函数时,只使用常规依赖注入就更简单了。不需要魔法。
设计一个可以运行命令的接口(例如CommandExecutor),然后将其中一个接口作为运行命令所需的任何函数的输入。然后,您可以在测试期间提供一个满足接口的模拟实现(手工构建,或者使用您选择的工具(如GoMock)生成)。为您的生产代码提供真正的实现(它调用exec包)。您的模拟实现甚至可以对参数进行断言,以便您知道该命令正在被“正确执行”。
发布于 2022-12-03 22:07:56
我所知道的最佳方法是使用多态性。你走在正确的轨道上。在我创建的https://github.com/schollii/go-test-mock-exec-command上有一个详细的解释,因为当我搜索如何模拟os/exec时,我所能找到的只是另一个答案中提到的env变量技术。这种方法是绝对没有必要的,正如我链接到的git的自述自述的那样,它所需要的只是一点多态。
摘要基本上如下:
exec.Cmd创建一个接口类,该类只有应用程序(或模块)代码要使用的必要方法exec.Cmd )在应用程序代码中,它将如下所示:
type IShellCommand interface {
Run() error
}
type execShellCommand struct {
*exec.Cmd
}
func newExecShellCommander(name string, arg ...string) IShellCommand {
execCmd := exec.Command(name, arg...)
return execShellCommand{Cmd: execCmd}
}
// override this in tests to mock the git shell command
var shellCommander = newExecShellCommander
func myFuncThatUsesExecCmd() {
cmd := shellCommander("git", "rev-parse", "--abbrev-ref", "HEAD")
err := cmd.Run()
if err != nil {
// handle error
} else {
// process & handle output
}
}在测试方面,它看起来如下所示:
type myShellCommand struct {
RunnerFunc func() error
}
func (sc myShellCommand) Run() error {
return sc.RunnerFunc()
}
func Test_myFuncThatUsesExecCmd(t *testing.T) {
// temporarily swap the shell commander
curShellCommander := shellCommander
defer func() { shellCommander = curShellCommander }()
shellCommander = func(name string, arg ...string) IShellCommand {
fmt.Printf("exec.Command() for %v called with %v and %v\n", t.Name(), name, arg)
return myShellCommand{
RunnerFunc: func() error {
return nil
},
}
}
// now that shellCommander is mocked, call the function that we want to test:
myFuncThatUsesExecCmd()
// do checks
}https://stackoverflow.com/questions/71102318
复制相似问题