免责声明:祝你圣诞快乐,我希望我的问题不会打扰你!
sample.go:
package main import( "fmt" "os" ) type sample struct { value int64 } func (s sample) useful() { if s.value == 0 { fmt.Println("Error: something is wrong!") os.Exit(1) } else { fmt.Println("May the force be with you!") } } func main() { s := sample{42} s.useful() s.value = 0 s.useful() } // output: // May the force be with you! // Error: something is wrong! // exit status 1
我做了很多关于如何在golang测试中使用接口的研究.但到目前为止,我还是无法彻底解决这个问题.至少我无法看到界面如何帮助我,当我需要“模拟”(道歉使用这个词)golang std.像“fmt”这样的库包.
我想出了两个场景:
>使用os / exec测试命令行界面
>包装fmt包所以我有控制权并且能够检查输出字符串
我不喜欢这两种情况:
>我经历了实际的命令行一个复杂而不具备性能(见下文).也可能有可移植性问题.
>我相信这是要走的路,但我担心包装fmt包可能需要做很多工作(至少包装测试的时间包结果是一项非常重要的任务(https://github.com/finklabs/ttime)).
这里的实际问题:还有另一种(更好/更简单/惯用)方式吗?
注意:我想在纯golang中执行此操作,我对下一个测试框架不感兴趣.
cli_test.go:
package main import( "os/exec" "testing" ) func TestCli(t *testing.T) { out,err := exec.Command("go run sample.go").Output() if err != nil { t.Fatal(err) } if string(out) != "May the force be with you!\nError: this is broken and not useful!\nexit status 1" { t.Fatal("There is something wrong with the CLI") } }
Kerningham’s Book的第11章为这个问题提供了一个很好的解决方案.
诀窍是将对fmt.Printline()的调用更改为调用
fmt.Fprint(out,…)其中out初始化为os.Stdout
诀窍是将对fmt.Printline()的调用更改为调用
fmt.Fprint(out,…)其中out初始化为os.Stdout
这可以在测试工具中覆盖到new(bytes.Buffer)允许
测试以捕获输出.
见https://github.com/adonovan/gopl.io/blob/master/ch11/echo/echo.go和
https://github.com/adonovan/gopl.io/blob/master/ch11/echo/echo_test.go
由OP编辑…
sample.go:
package main import( "fmt" "os" "io" ) var out io.Writer = os.Stdout // modified during testing var exit func(code int) = os.Exit type sample struct { value int64 } func (s sample) useful() { if s.value == 0 { fmt.Fprint(out,"Error: something is wrong!\n") exit(1) } else { fmt.Fprint(out,"May the force be with you!\n") } } func main() { s := sample{42} s.useful() s.value = 0 s.useful() } // output: // May the force be with you! // Error: this is broken and not useful! // exit status 1
cli_test.go:
package main import( "bytes" "testing" ) func TestUsefulPositive(t *testing.T) { bak := out out = new(bytes.Buffer) defer func() { out = bak }() s := sample{42} s.useful() if out.(*bytes.Buffer).String() != "May the force be with you!\n" { t.Fatal("There is something wrong with the CLI") } } func TestUsefulNegative(t *testing.T) { bak := out out = new(bytes.Buffer) defer func() { out = bak }() code := 0 osexit := exit exit = func(c int) { code = c } defer func() { exit = osexit }() s := sample{0} s.useful() if out.(*bytes.Buffer).String() != "Error: something is wrong!\n" { t.Fatal("There is something wrong with the CLI") } if code != 1 { t.Fatal("Wrong exit code!") } }