英文:
How to test code using the Go logging package glog ?
问题
我已经实现了一个包装 glog 的类型,这样我就可以在我的程序中为日志消息添加前缀,以标识日志的发出者,并且我可以根据发出者更改日志级别。
我该如何实现单元测试?问题在于 glog 将文本输出到 stdErr。
代码很简单,但我希望像其他代码一样进行单元测试并实现100%的覆盖率。这个编程工作已经很值得了。
英文:
I have implemented a type wrapping glog so that I can add a prefix to log message identifying the emitter of the log in my program and I can change the log level per emitter.
How could I implement the unit tests ? The problem is that glog outputs text to stdErr.
The code is trivial but I would like the have the unit test and 100% coverage like the rest of the code. This programming effort already payed.
答案1
得分: 4
捕获标准错误的测试代码:
package main
import (
"bytes"
"io"
"os"
"testing"
"github.com/golang/glog"
"strings"
)
func captureStderr(f func()) (string, error) {
old := os.Stderr // 保存真实的标准错误备份
r, w, err := os.Pipe()
if err != nil {
return "", err
}
os.Stderr = w
outC := make(chan string)
// 在单独的goroutine中复制输出,以防止打印阻塞
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
outC <- buf.String()
}()
// 调用要捕获标准错误的函数:
f()
// 恢复到正常状态
w.Close()
os.Stderr = old // 恢复真实的标准错误
return <-outC, nil
}
func TestGlogError(t *testing.T) {
stdErr, err := captureStderr(func() {
glog.Error("Test error")
})
if err != nil {
t.Errorf("不应该出错,而是出现错误:%+v", err)
}
if !strings.HasSuffix(strings.TrimSpace(stdErr), "Test error") {
t.Errorf("标准错误应该以 'Test error' 结尾,但它并不是:%s", stdErr)
}
}
运行测试:
go test -v
=== RUN TestGlogError
--- PASS: TestGlogError (0.00s)
PASS
ok command-line-arguments 0.007s
英文:
Test which captures stderr:
package main
import (
"bytes"
"io"
"os"
"testing"
"github.com/golang/glog"
"strings"
)
func captureStderr(f func()) (string, error) {
old := os.Stderr // keep backup of the real stderr
r, w, err := os.Pipe()
if err != nil {
return "", err
}
os.Stderr = w
outC := make(chan string)
// copy the output in a separate goroutine so printing can't block indefinitely
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
outC <- buf.String()
}()
// calling function which stderr we are going to capture:
f()
// back to normal state
w.Close()
os.Stderr = old // restoring the real stderr
return <-outC, nil
}
func TestGlogError(t *testing.T) {
stdErr, err := captureStderr(func() {
glog.Error("Test error")
})
if err != nil {
t.Errorf("should not be error, instead: %+v", err)
}
if !strings.HasSuffix(strings.TrimSpace(stdErr), "Test error") {
t.Errorf("stderr should end by 'Test error' but it doesn't: %s", stdErr)
}
}
running test:
go test -v
=== RUN TestGlogError
--- PASS: TestGlogError (0.00s)
PASS
ok command-line-arguments 0.007s
答案2
得分: 0
编写一个描述你的用法的接口。如果你使用V
方法,这可能不太美观,但是你已经有一个包装器,所以你已经完成了修复这个问题所需的艰苦工作。
对于你需要测试的每个包,定义以下接口:
type Logger interface {
Infoln(...interface{}) // 在这个包中实际使用的方法
}
然后,你可以通过在代码中不直接引用glog类型来轻松替换它。
英文:
Write an interface that describes your usage. This won't be very pretty if you use the V
method, but you have a wrapper so you've already done the hard work that fixing that would entail.
For each package you need to test, define
type Logger interface {
Infoln(...interface{}) // the methods you actually use in this package
}
And then you can easily swap it out by not referring to glog types directly in your code.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论