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

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

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 (
	&quot;bytes&quot;
	&quot;io&quot;
	&quot;os&quot;
	&quot;testing&quot;

	&quot;github.com/golang/glog&quot;
	&quot;strings&quot;
)

func captureStderr(f func()) (string, error) {
	old := os.Stderr // keep backup of the real stderr
	r, w, err := os.Pipe()
	if err != nil {
		return &quot;&quot;, err
	}
	os.Stderr = w

	outC := make(chan string)
	// copy the output in a separate goroutine so printing can&#39;t block indefinitely
	go func() {
		var buf bytes.Buffer
		io.Copy(&amp;buf, r)
		outC &lt;- 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 &lt;-outC, nil
}

func TestGlogError(t *testing.T) {
	stdErr, err := captureStderr(func() {
		glog.Error(&quot;Test error&quot;)
	})
	if err != nil {
		t.Errorf(&quot;should not be error, instead: %+v&quot;, err)
	}
	if !strings.HasSuffix(strings.TrimSpace(stdErr), &quot;Test error&quot;) {
		t.Errorf(&quot;stderr should end by &#39;Test error&#39; but it doesn&#39;t: %s&quot;, 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.

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:

确定