Testing 如何处理;fmt“;用于CLI测试的golang库包
免责声明:祝你圣诞快乐,我希望我的问题不会打扰你 sample.go:Testing 如何处理;fmt“;用于CLI测试的golang库包,testing,go,mocking,Testing,Go,Mocking,免责声明:祝你圣诞快乐,我希望我的问题不会打扰你 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
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
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
我做了很多关于如何在golang测试中使用接口的研究。但到目前为止,我还不能完全理解这一点。至少当我需要“mock”(抱歉使用这个词)golang标准库包(如“fmt”)时,我看不出接口如何帮助我
我想出了两个方案:
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")
}
}
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!")
}
}
克宁汉姆书的第11章很好地解决了这个问题。 诀窍是将对fmt.Printline()的调用更改为对 fmt.Fprint(out,…),其中out初始化为os.Stdout 这可以在测试线束中覆盖为新的(bytes.Buffer),从而允许 测试以捕获输出 看到和 编辑:OP。。。 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
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(
"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")
}
}
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!")
}
}
我是不是错过了什么,还是你在说什么 基本上,它是这样工作的:在
*\u test.go
文件中,您需要遵守约定示例[[T][\u M]]
,其中T
是类型的占位符,M
是要在Godoc中将可测试示例显示为示例代码的方法的占位符。如果只调用函数Example()
,则代码将显示为包示例
在示例代码的最后一行下面,您可以放置如下注释
// Output:
// Foo
现在go test
将确保可测试示例函数准确地输出//输出:
(包括空格),否则将导致测试失败
下面是一个可测试示例的实际示例
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'
}
编辑:看一看哇,我不知道派克写了一本书。请说明这本书的书名或参考书目好吗。我喜欢你的建议。我即将像那样重构我的代码,并向您报告。非常感谢你!Go编程语言Alan A.A.Donovan·Brian W.Kernighan于2015年10月26日出版平装本,11月20日出版电子书Addison Wesley;380pp;ISBN:978-0134190440我按照你的建议重构了代码。我希望你不介意我在你的回答中添加了我的想法,以使其明确。如果我误解了什么,请改变它。顺便说一下,os.Exit.Looks似乎有问题。正如您所说,os.Exit存在一个问题。很难对调用exit的函数进行单元测试,因为这将中止单元测试。最好是返回某种错误代码,这样就行了。但最好避免调用Exit,而是返回一个有用的错误(通常情况下为零)。看见