为了账号安全,请及时绑定邮箱和手机立即绑定

如何处理用于 CLI 测试的“fmt”golang 库包

如何处理用于 CLI 测试的“fmt”golang 库包

Go
MM们 2021-11-29 19:21:16
示例.go:package mainimport(    "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 mainimport(    "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")    }}
查看完整描述

2 回答

?
手掌心

TA贡献1942条经验 获得超3个赞

Kerningham 的书的第 11 章很好地解决了这个问题。诀窍是将对 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 。走


由 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!")

    }

}


查看完整回答
反对 回复 2021-11-29
?
白衣染霜花

TA贡献1796条经验 获得超10个赞

基本上,它是这样工作的:在*_test.go文件中,您需要遵守约定Example[[T][_M]],其中T是类型M的占位符和要在 Godoc 中将可测试示例显示为示例代码的方法的占位符。如果刚刚调用该函数Example(),则代码将显示为包示例。


在示例代码的最后一行下方,您可以添加这样的注释


// Output:

// Foo

现在go test将确保可测试的示例函数要么完全输出下面的所有内容// Output:(包括空格),要么会使测试失败。


这是可测试示例的实际示例


func ExampleMongoStore_Get() {


  sessionId := "ExampleGetSession"


  data, err := ms.Get(sessionId)


  if err == sessionmw.ErrSessionNotFound {


    fmt.Printf("Session '%s' not found\n", sessionId)


    data = make(map[string]interface{})

    data["foo"] = "bar"


    ms.Save(sessionId, data)

  }


  loaded, _ := ms.Get(sessionId)

  fmt.Printf("Loaded value '%s' for key '%s' in session '%s'",

    loaded["foo"],

    "foo", sessionId)

  // Output:

  // Session 'ExampleGetSession' not found

  // Loaded value 'bar' for key 'foo' in session 'ExampleGetSession'

}


查看完整回答
反对 回复 2021-11-29
  • 2 回答
  • 0 关注
  • 148 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信