英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论