Go test terminal output

Viewed 129

The Go test tutorials I have searched use the return value to the testing.

I would like to write a test that checks the output from the terminal.

Here is an example of what I want to achieve:

main.go

package main

import (
    "fmt"
    "os"
    "strings"
)

func main() {
    arguments := os.Args   

    fmt.Println(strings.ToUpper(arguments[1]))
}

The test I have played around with

main_test.go

package main

import (
    "log"
    "os/exec"
    "testing"
)

type checkResult struct {
    inp      string
    expected string
}

var testCases = []checkResult{
    {"Go <3", "GO <3"},
}

func TestMain(t *testing.T) {
    for _, test := range testCases {
        output, err := exec.Command("go run main.go ", test.inp).Output()
        if err != nil {
            log.Fatal(err)
        }
        if string(output) != (test.expected) {
            t.Fatal("Expected result is wrong")
        }
    }
}
1 Answers

If you change design of your CLI little bit, it will be more testable. Create global variable of type io.Writter and use fmt.Fprintf to write your output into os.Stdout.

main.go

package main

import (
    "fmt"
    "io"
    "os"
    "strings"
)

var out io.Writer = os.Stdout

func main() {
    arguments := os.Args

    fmt.Fprintf(out, "%s\n", strings.ToUpper(arguments[1]))
}

Now it is no problem to set variable out to redirect output and os.Args to CLI arguments in test scenario.

main_test.go

package main

import (
    "bytes"
    "os"
    "testing"
)

func TestOutput(t *testing.T) {
    testData := []struct {
        Args   []string
        Output string
    }{
        {
            Args:   []string{"./macli", "hello"},
            Output: "HELLO\n",
        },
        {
            Args:   []string{"", "Go <3"},
            Output: "GO <3\n",
        },
    }
    for _, test := range testData {
        // Init test
        os.Args = test.Args
        out = bytes.NewBuffer(nil)
        // Run test
        main()
        // Evaluate output
        if actual := out.(*bytes.Buffer).String(); actual != test.Output {
            t.Errorf("expected '%s', but got '%s'", test.Output, actual)
        }
    }
}

For more detailed description see this article

Related