我有这个功能,在某些情况下记录错误:
func readByte(/*...*/){
// ...
if err != nil {
fmt.Println("ERROR")
log.Print("Couldn't read first byte")
return
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
现在,在测试文件中,我想检查此函数的输出错误:
c.Assert(OUTPUT, check.Matches, "teste")
Run Code Online (Sandbox Code Playgroud)
我该如何访问日志?我试图放一个缓冲区,但它没有用.在不更改readByte函数代码的情况下捕获此日志的正确方法是什么?
pet*_*rSO 18
例如,
readbyte_test.go:
package main
import (
"bytes"
"fmt"
"io"
"log"
"os"
"testing"
)
func readByte( /*...*/ ) {
// ...
err := io.EOF // force an error
if err != nil {
fmt.Println("ERROR")
log.Print("Couldn't read first byte")
return
}
// ...
}
func TestReadByte(t *testing.T) {
var buf bytes.Buffer
log.SetOutput(&buf)
defer func() {
log.SetOutput(os.Stderr)
}()
readByte()
t.Log(buf.String())
}
Run Code Online (Sandbox Code Playgroud)
输出:
$ go test -v readbyte_test.go
=== RUN TestReadByte
ERROR
--- PASS: TestReadByte (0.00s)
readbyte_test.go:30: 2017/05/22 16:41:00 Couldn't read first byte
PASS
ok command-line-arguments 0.004s
$
Run Code Online (Sandbox Code Playgroud)
dar*_*ing 12
如果您的测试是并发运行的(例如,测试 or 时http Server)Client,您可能会遇到写入缓冲区和读取缓冲区之间的竞争。我们可以将输出重定向到 anos.Pipe并使用 a进行bufio.Scanner阻塞,直到使用该Scan()方法写入输出,而不是使用缓冲区。
os.Pipe以下是创建stdliblog包并将其设置为使用管道的示例。请注意我在这里使用testify/assert 包:
func mockLogger(t *testing.T) (*bufio.Scanner, *os.File, *os.File) {
reader, writer, err := os.Pipe()
if err != nil {
assert.Fail(t, "couldn't get os Pipe: %v", err)
}
log.SetOutput(writer)
return bufio.NewScanner(reader), reader, writer
}
Run Code Online (Sandbox Code Playgroud)
*os.File返回对象,以便可以使用延迟函数正确关闭它们。在这里我只是打印,stdout因为如果关闭时出现一些奇怪的错误,我个人不想让测试失败。t.Errorf但是,如果您愿意,这很可能是另一个调用或类似的调用:
func resetLogger(reader *os.File, writer *os.File) {
err := reader.Close()
if err != nil {
fmt.Println("error closing reader was ", err)
}
if err = writer.Close(); err != nil {
fmt.Println("error closing writer was ", err)
}
log.SetOutput(os.Stderr)
}
Run Code Online (Sandbox Code Playgroud)
然后在您的测试中您将具有以下模式:
scanner, reader, writer := mockLogger(t) // turn this off when debugging or developing as you will miss output!
defer resetLogger(reader, writer)
// other setup as needed, getting some value for thing below
go concurrentAction()
scanner.Scan() // blocks until a new line is written to the pipe
got := scanner.Text() // the last line written to the scanner
msg := fmt.Sprintf("your log message with thing %v you care about", thing)
assert.Contains(t, got, msg)
Run Code Online (Sandbox Code Playgroud)
最后, concurrentAction() 函数正在调用一个log函数(或方法,如果使用 a ,则该包实际上与上面的调用log.logger行为相同),如下所示:log.SetOutput()
// doing something, getting value for thing
log.Printf("your log message with the thing %v you care about", thing)
Run Code Online (Sandbox Code Playgroud)