how do you test golang command line output
go, testing
Solution
This is a bad example of parsing command line args, but it shows the framework I use to test command line args in my apps.
main.go
package main
import (
"log"
"os"
)
func main() {
var city string
parseFlags(&city, os.Args)
log.Println(city)
}
func parseFlags(result *string, args []string) {
cityDefault := "San Francisco"
switch len(args) {
case 3:
*result = args[2]
default:
*result = cityDefault
}
}
main_unit_test.go
package main
import (
"log"
"testing"
)
// TestParseFlags - test our command line flags
func TestParseFlags(t *testing.T) {
var parseFlagsTests = []struct {
flags []string // input flags to the command line
expected string // expected
}{
{[]string{"/fake/loc/main"}, "San Francisco"},
{[]string{"/fake/loc/main", "-c", "Los Angeles"}, "Los Angeles"},
{[]string{"/fake/loc/main", "--city", "Los Angeles"}, "Los Angeles"},
}
for _, tt := range parseFlagsTests {
var output string
parseFlags(&output, tt.flags)
if output != tt.expected {
t.Errorf("expected: %s, actual: %s", tt.expected, output)
}
}
}
I typically use this package to parse command line args in all of my apps. And I'll structure my code as follows (tests not shown, but they generally follow the gist of the test shown above):
main.go
package main
import (
"log"
"os"
"myDir/cli"
)
func main() {
// Grab the user inputed CLI flags
cliFlags := cli.FlagsStruct{}
cliErr := cli.StartCLI(&cliFlags, os.Args)
if cliErr != nil {
log.Println("Error grabbing command line args")
log.Fatal(cliErr)
}
// Do stuff ...
}
/myDir/cli.go
package cli
import "github.com/urfave/cli"
// FlagsStruct - holds command line args
type FlagsStruct struct {
MyFlag string
}
// StartCLI - gathers command line args
func StartCLI(cliFlags *FlagsStruct, args []string) error {
app := cli.NewApp()
app.Action = func(ctx *cli.Context) error {
MyFlag := ctx.GlobalString("my-flag")
// build the cli struct to send back to main
cliFlags.MyFlag = MyFlag
return nil
}
app.Authors = []cli.Author{
{
Email: "my@email.com",
Name: "Adam Hanna",
},
}
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "my-flag, f",
Usage: "My flag usage goes here",
Value: "myDefault",
},
}
app.Name = "myAppName"
app.Usage = "My App's Usage"
app.Version = "0.0.1"
return app.Run(args)
}
Problem
I'd like to test the output of a golang command line app, but I'm not quite sure how to do that with go's testing library. Let's say I have a program like this: ``` package main import ( "flag" "fmt" ) func main() { const ( cityDefault = "San Francisco" cityDoc = "the city you want the forecast for" ) var city string flag.StringVar(&city, "city", cityDefault, cityDoc) flag.StringVar(&city, "c", cityDefault, cityDoc) flag.Parse() fmt.Println(city) } ``` I'd like to test that both of these: ``` $ ./myapp -c "Los Angeles" $ ./myapp -city "Los Angeles" ``` ... output `Lost Angeles`. So, I guess the question is, how do you go about integration testing the output of a golang command line app?