1

I am trying to test my CLI application written with Cobra, specifically to test if subcommands are writing correctly to STDOUT. For this, I try to redirect the output from STDOUT to my buffer. Unfortunately, for whatever reason, the SetOut() function does not behave as expected on subcommands obtained via a call to Commands().

How can I correctly call SetOut() on subcommands in Cobra?

Here is my code:

package cmd

import (
    "os"
    "testing"
    "bytes"
    "io/ioutil"
    "github.com/spf13/cobra"
)

func NewCmd() *cobra.Command {
    cmd := &cobra.Command{}
    cmd.AddCommand(NewChildCmd())
    return cmd
}

func NewChildCmd() *cobra.Command {
    cmd := &cobra.Command{
        Use:   "child",
        Run: func(cmd *cobra.Command, args []string) {
                os.Stdout.WriteString("TEST\n")
        },
    }
    return cmd
}

func TestChild(t *testing.T) {
    cmd := NewCmd()
    buffer := new(bytes.Buffer)

    subCommands := cmd.Commands()
    for i := range subCommands {
        subCommands[i].SetOut(buffer)
    }

    cmd.SetOut(buffer)
    cmd.SetArgs([]string{"child"})
    cmd.Execute()
    out, err := ioutil.ReadAll(buffer)
    if err != nil {
        t.Fatal(err)
    }
    if string(out) != "child" {
        t.Fatalf("Expected \"TEST\", got \"%s\"", string(out))
    }
}

And here is the test output:

TEST
--- FAIL: TestChild (0.00s)
    cmd/my_test.go:44: Expected "TEST", got ""
FAIL
FAIL    cmd 0.004s
FAIL
Petr
  • 486
  • 7
  • 19

1 Answers1

8

Apparently, SetOut() is not able to change the output sent directly to os.Stdout, instead, cmd.Println() has to be used, then everything works as expected.

Petr
  • 486
  • 7
  • 19
  • Awesome finding! Thanks for the answer! I was going nuts for a couple of days due to this – bidon Jun 29 '22 at 09:52