并发测试答案
如果您的测试同时运行(例如,在测试http Server 或Client 时),您可能会遇到写入缓冲区和读取缓冲区之间的竞争。我们可以将输出重定向到os.Pipe,而不是缓冲区,并使用bufio.Scanner 进行阻塞,直到使用Scan() 方法写入输出。
这里是创建os.Pipe 并设置stdlib log 包以使用管道的示例。注意我在这里使用testify/assert package:
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
}
*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)
}
然后在你的测试中你会得到这个模式:
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)
最后,concurrentAction() 函数正在调用 log 函数(或方法,如果使用 log.logger,包的行为实际上与上面的 log.SetOutput() 调用相同)如:
// doing something, getting value for thing
log.Printf("your log message with the thing %v you care about", thing)