我有一个我想测试的简单功能:
func (t *Thing) print(min_verbosity int, message string) {
if t.verbosity >= minv {
fmt.Print(message)
}
}
但是如何测试函数实际发送到标准输出的内容? Test::Output在Perl中做了我想做的事。我知道我可以编写所有自己的样板来在Go中执行相同操作(如here所述):
orig = os.Stdout
r,w,_ = os.Pipe()
thing.print("Some message")
var buf bytes.Buffer
io.Copy(&buf, r)
w.Close()
os.Stdout = orig
if(buf.String() != "Some message") {
t.Error("Failure!")
}
但是,对于每一项测试来说,这都是额外的工作。我希望有更标准的方法,或者可能是一个抽象库来处理这个问题。
答案 0 :(得分:24)
还有一件事要记住,没有什么可以阻止你编写函数来避免样板。
例如,我有一个使用log
的命令行应用程序,我写了这个函数:
func captureOutput(f func()) string {
var buf bytes.Buffer
log.SetOutput(&buf)
f()
log.SetOutput(os.Stderr)
return buf.String()
}
然后像这样使用它:
output := captureOutput(func() {
client.RemoveCertificate("www.example.com")
})
assert.Equal("removed certificate www.example.com\n", output)
答案 1 :(得分:13)
你可以做两件事之一。第一种是使用Examples。
该软件包还运行并验证示例代码。示例函数可以包括以“Output:”开头的结束行注释,并在运行测试时与函数的标准输出进行比较。 (比较忽略前导和尾随空格。)这些是示例的示例:
func ExampleHello() {
fmt.Println("hello")
// Output: hello
}
第二个(更合适的是,IMO)是为你的IO使用虚假功能。在您的代码中,您可以:
var myPrint = fmt.Print
func (t *Thing) print(min_verbosity int, message string) {
if t.verbosity >= minv {
myPrint(message) // N.B.
}
}
在你的测试中:
func init() {
myPrint = fakePrint // fakePrint records everything it's supposed to print.
}
func Test...
另一种选择是在生产代码中使用fmt.Fprintf
io.Writer
os.Stdout
,但在测试中可以说bytes.Buffer
。
答案 2 :(得分:1)
您可以考虑在函数中添加一个return语句,以返回实际打印出来的字符串。
func (t *Thing) print(min_verbosity int, message string) string {
if t.verbosity >= minv {
fmt.Print(message)
return message
}
return ""
}
现在,您的测试可以根据预期的字符串(而不是打印输出)检查返回的字符串。也许与测试驱动开发(TDD)更加一致。
而且,在您的生产代码中,不需要更改任何内容,因为如果您不需要,则不必分配函数的返回值。