如何测试 Golang 命令行输出?

huangapple go评论92阅读模式
英文:

how do you test golang command line output

问题

我想测试一个使用golang命令行应用程序的输出,但我不太确定如何使用go的测试库来做到这一点。

假设我有一个像这样的程序:

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)
}

我想测试这两个命令的输出:

$ ./myapp -c "Los Angeles"
$ ./myapp -city "Los Angeles"

...输出应该是 Lost Angeles。所以,我猜问题是,你如何进行集成测试来测试golang命令行应用程序的输出?

英文:

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?

答案1

得分: 4

这是一个解析命令行参数的不好的示例,但它展示了我在应用程序中测试命令行参数时使用的框架。

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)
		}
	}
}

我通常使用这个包来解析我所有应用程序中的命令行参数。我会按照以下结构编写代码(未显示测试代码,但它们通常遵循上面示例的主要思路):

main.go

package main

import (
	"log"
	"os"

	"myDir/cli"
)

func main() {
	// 获取用户输入的命令行标志
	cliFlags := cli.FlagsStruct{}
	cliErr := cli.StartCLI(&cliFlags, os.Args)
	if cliErr != nil {
		log.Println("获取命令行参数时出错")
		log.Fatal(cliErr)
	}

	// 做一些事情...
}

/myDir/cli.go

package cli

import "github.com/urfave/cli"

// FlagsStruct - 保存命令行参数
type FlagsStruct struct {
	MyFlag string
}

// StartCLI - 收集命令行参数
func StartCLI(cliFlags *FlagsStruct, args []string) error {
	app := cli.NewApp()
	app.Action = func(ctx *cli.Context) error {
		MyFlag := ctx.GlobalString("my-flag")

		// 构建要发送回主函数的 cli 结构体
		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: "这里是我的标志用法",
			Value: "myDefault",
		},
	}
	app.Name = "myAppName"
	app.Usage = "我的应用程序的用法"
	app.Version = "0.0.1"
	return app.Run(args)
}
英文:

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)
}

答案2

得分: 2

如何使用 test "$(./myapp -c "洛杉矶")" = "洛杉矶" 进行测试?
对于 -city 参数也是一样。这与 Go 无关,只需让你的集成测试套件执行测试即可。

英文:

How about test "$(./myapp -c "Los Angeles")" = "Los Angeles"
and the same for -city. This has nothing to do with Go, just let your integration test suite do the test.

huangapple
  • 本文由 发表于 2014年12月4日 01:26:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/27277917.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定