使用Go日志包glog如何测试代码?

huangapple go评论110阅读模式
英文:

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

捕获标准错误的测试代码:

  1. package main
  2. import (
  3. "bytes"
  4. "io"
  5. "os"
  6. "testing"
  7. "github.com/golang/glog"
  8. "strings"
  9. )
  10. func captureStderr(f func()) (string, error) {
  11. old := os.Stderr // 保存真实的标准错误备份
  12. r, w, err := os.Pipe()
  13. if err != nil {
  14. return "", err
  15. }
  16. os.Stderr = w
  17. outC := make(chan string)
  18. // 在单独的goroutine中复制输出,以防止打印阻塞
  19. go func() {
  20. var buf bytes.Buffer
  21. io.Copy(&buf, r)
  22. outC <- buf.String()
  23. }()
  24. // 调用要捕获标准错误的函数:
  25. f()
  26. // 恢复到正常状态
  27. w.Close()
  28. os.Stderr = old // 恢复真实的标准错误
  29. return <-outC, nil
  30. }
  31. func TestGlogError(t *testing.T) {
  32. stdErr, err := captureStderr(func() {
  33. glog.Error("Test error")
  34. })
  35. if err != nil {
  36. t.Errorf("不应该出错,而是出现错误:%+v", err)
  37. }
  38. if !strings.HasSuffix(strings.TrimSpace(stdErr), "Test error") {
  39. t.Errorf("标准错误应该以 'Test error' 结尾,但它并不是:%s", stdErr)
  40. }
  41. }

运行测试:

  1. go test -v
  2. === RUN TestGlogError
  3. --- PASS: TestGlogError (0.00s)
  4. PASS
  5. ok command-line-arguments 0.007s
英文:

Test which captures stderr:

  1. package main
  2. import (
  3. &quot;bytes&quot;
  4. &quot;io&quot;
  5. &quot;os&quot;
  6. &quot;testing&quot;
  7. &quot;github.com/golang/glog&quot;
  8. &quot;strings&quot;
  9. )
  10. func captureStderr(f func()) (string, error) {
  11. old := os.Stderr // keep backup of the real stderr
  12. r, w, err := os.Pipe()
  13. if err != nil {
  14. return &quot;&quot;, err
  15. }
  16. os.Stderr = w
  17. outC := make(chan string)
  18. // copy the output in a separate goroutine so printing can&#39;t block indefinitely
  19. go func() {
  20. var buf bytes.Buffer
  21. io.Copy(&amp;buf, r)
  22. outC &lt;- buf.String()
  23. }()
  24. // calling function which stderr we are going to capture:
  25. f()
  26. // back to normal state
  27. w.Close()
  28. os.Stderr = old // restoring the real stderr
  29. return &lt;-outC, nil
  30. }
  31. func TestGlogError(t *testing.T) {
  32. stdErr, err := captureStderr(func() {
  33. glog.Error(&quot;Test error&quot;)
  34. })
  35. if err != nil {
  36. t.Errorf(&quot;should not be error, instead: %+v&quot;, err)
  37. }
  38. if !strings.HasSuffix(strings.TrimSpace(stdErr), &quot;Test error&quot;) {
  39. t.Errorf(&quot;stderr should end by &#39;Test error&#39; but it doesn&#39;t: %s&quot;, stdErr)
  40. }
  41. }

running test:

  1. go test -v
  2. === RUN TestGlogError
  3. --- PASS: TestGlogError (0.00s)
  4. PASS
  5. ok command-line-arguments 0.007s

答案2

得分: 0

编写一个描述你的用法的接口。如果你使用V方法,这可能不太美观,但是你已经有一个包装器,所以你已经完成了修复这个问题所需的艰苦工作。

对于你需要测试的每个包,定义以下接口:

  1. type Logger interface {
  2. Infoln(...interface{}) // 在这个包中实际使用的方法
  3. }

然后,你可以通过在代码中不直接引用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

  1. type Logger interface {
  2. Infoln(...interface{}) // the methods you actually use in this package
  3. }

And then you can easily swap it out by not referring to glog types directly in your code.

huangapple
  • 本文由 发表于 2016年12月21日 00:41:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/41247206.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定