unit-testing - 如何在 go 中实现 CLI 命令的单元测试

标签 unit-testing go go-cobra

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

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

  • 如果我错了,请纠正我。

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

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

    最佳答案

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

    您需要的第一件事是将 CLI 作为接口(interface)。这将在一个名为“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
    }
    

    同样,在名为 test 的包中会有一个模拟 cli这将实现 cli 接口(interface),它还将实现 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将通过。

    关于unit-testing - 如何在 go 中实现 CLI 命令的单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59709345/

    相关文章:

    c++ - GMock 死亡案例 - 模拟函数未被调用

    go - 将CreationTimeStamp类型转换为字符串

    java - 如果该参数的状态已更改,如何验证传递的参数是否具有正确的参数?

    go - 我应该如何在 Go 中组织结构、变量和接口(interface)?

    go - Reader 从不读取 `StdoutPipe`

    go - 为什么我会根据调用 BindPFlag 的位置收到零指针错误?

    json - 如何提供 JSON 数组作为 cobra cli 的参数

    bash - 如何将 Go cmd 应用程序提供为高效应用程序

    visual-studio-2010 - Visual Studio 负载测试以数据驱动的方式模拟许多用户?

    node.js - 对 Promise 结果运行多个测试 - Mocha