8

我正在启动一个使用 spf13/cobra 的新 OSS CLI 工具。作为 golang 的新手,我很难找出单独测试命令的最佳方法。谁能给我一个如何测试命令的例子?几个警告:

  1. 你不能从你的 init 函数返回一个 cobra.Command
  2. 你不能get_test.go在 cmd 目录中......我的印象是golang的最佳实践。
  3. 我是 golang 新手,请放轻松 :sweat_smile:

如果我错了,请纠正我。

这是我要测试的 cmd:https ://github.com/sahellebusch/raider/blob/3-add-get-alerts/cmd/get.go 。

开放的想法,建议,批评,无论什么。

4

2 回答 2

5

使用 go 实现 CLI 有多种方法。这是我开发的 CLI 的基本结构,主要受 docker CLI 的影响,我也添加了单元测试。

您需要的第一件事是将 CLI 作为接口。这将在一个名为“cli”的包中。

package cli

type Cli interface {
     // Have interface functions here
     sayHello() error
}

这将由 2 个 cli 实现:HelloCli(我们真正的 CLI)和 MockCli(用于单元测试)

package cli

type HelloCli struct {
}

func NewHelloCli() *HelloCli {
    cli := &HelloCli{
    }
    return cli
}

在这里,HelloCli 将实现 sayHello 函数,如下所示。

package cli

func (cli *HelloCli) SayHello() error {
    // Implement here
}

类似地,在一个名为的包中会有一个模拟 cli test,它将实现 cli 接口,它还将实现 sayHello 函数。

package test

type MockCli struct {
    }

    func NewMockCli() *HelloCli {
        cli := &MockCli{
        }
        return cli
    }

func (cli *MockCli) SayHello() error {
        // Mock implementation here
    }

现在我将展示如何添加命令。首先,我将拥有主包,这是我将添加所有新命令的地方。

package main

func newCliCommand(cli cli.Cli) *cobra.Command {
    cmd := &cobra.Command{
        Use:   "foo <command>"
    }

    cmd.AddCommand(
        newHelloCommand(cli),
    )
    return cmd
}

func main() {
    helloCli := cli.NewHelloCli()
    cmd := newCliCommand(helloCli)
    if err := cmd.Execute(); err != nil {
        // Do something here if execution fails
    }
}

func newHelloCommand(cli cli.Cli) *cobra.Command {
    cmd := &cobra.Command{
        Use:   "hello",
        Short: "Prints hello",
        Run: func(cmd *cobra.Command, args []string) {
            if err := pkg.RunHello(cli, args[0]); err != nil {
                // Do something if command fails
            }
        },
        Example: "  foo hello",
    }
    return cmd
}

在这里,我有一个名为hello. 接下来,我将在一个名为“pkg”的单独包中实现实现。

package pkg

func RunHello(cli cli.Cli) error {
    // Do something in this function
    cli.SayHello()
    return nil
}

单元测试也将包含在此包中名为hello_test.

package pkg

func TestRunHello(t *testing.T) {
    mockCli := test.NewMockCli()

    tests := []struct {
        name     string
    }{
        {
            name:     "my test 1",
        },
        {
            name:     "my test 2"
        },
    }
    for _, tst := range tests {
        t.Run(tst.name, func(t *testing.T) {
            err := SayHello(mockCli)
            if err != nil {
                t.Errorf("error in SayHello, %v", err)
            }
        })
    }
}

当你执行foo hello时,HelloCli将被传递给 sayHello() 函数,当你运行单元测试时,MockCli将被传递。

于 2020-01-13T09:51:27.363 回答
2

你可以检查它cobra自己是如何做到的 - https://github.com/spf13/cobra/blob/master/command_test.go

基本上,您可以将实际的命令逻辑(运行函数)重构为一个单独的函数并测试该函数。您可能想要正确命名您的函数,而不是仅仅调用它run

于 2020-01-13T07:36:18.113 回答