说,我有以下代码打印一些日志消息.我如何测试是否记录了正确的消息?作为log.Fatal调用os.Exit(1),测试失败.
package main
import (
"log"
)
func hello() {
log.Print("Hello!")
}
func goodbye() {
log.Fatal("Goodbye!")
}
func init() {
log.SetFlags(0)
}
func main() {
hello()
goodbye()
}
Run Code Online (Sandbox Code Playgroud)
以下是假设性测试:
package main
import (
"bytes"
"log"
"testing"
)
func TestHello(t *testing.T) {
var buf bytes.Buffer
log.SetOutput(&buf)
hello()
wantMsg := "Hello!\n"
msg := buf.String()
if msg != wantMsg {
t.Errorf("%#v, wanted %#v", msg, wantMsg)
}
}
func TestGoodby(t *testing.T) {
var buf bytes.Buffer
log.SetOutput(&buf)
goodbye()
wantMsg := "Goodbye!\n"
msg := buf.String()
if msg != wantMsg {
t.Errorf("%#v, wanted %#v", msg, wantMsg)
}
}
Run Code Online (Sandbox Code Playgroud)
Von*_*onC 11
这类似于" 如何os.Exit()在Go中测试场景 ":你需要实现自己的记录器,默认情况下重定向到log.xxx(),但是在测试时给你机会替换log.Fatalf()你自己的函数(不调用os.Exit(1))
我在测试os.Exit()呼叫方面做了同样的事情exit/exit.go:
exiter = New(func(int) {})
exiter.Exit(3)
So(exiter.Status(), ShouldEqual, 3)
Run Code Online (Sandbox Code Playgroud)
(这里,我的"退出"功能是空的,什么都不做)
Poh*_*How 10
如果您正在使用logrus,现在有一个选项可以定义此提交中引入的v1.3.0 中的退出函数。所以你的测试可能看起来像:
func Test_X(t *testing.T) {
cases := []struct{
param string
expectFatal bool
}{
{
param: "valid",
expectFatal: false,
},
{
param: "invalid",
expectFatal: true,
},
}
defer func() { log.StandardLogger().ExitFunc = nil }()
var fatal bool
log.StandardLogger().ExitFunc = func(int){ fatal = true }
for _, c := range cases {
fatal = false
X(c.param)
assert.Equal(t, c.expectFatal, fatal)
}
}
Run Code Online (Sandbox Code Playgroud)
我使用以下代码来测试我的功能.在xxx.go中:
var logFatalf = log.Fatalf
if err != nil {
logFatalf("failed to init launcher, err:%v", err)
}
Run Code Online (Sandbox Code Playgroud)
在xxx_test.go中:
// TestFatal is used to do tests which are supposed to be fatal
func TestFatal(t *testing.T) {
origLogFatalf := logFatalf
// After this test, replace the original fatal function
defer func() { logFatalf = origLogFatalf } ()
errors := []string{}
logFatalf = func(format string, args ...interface{}) {
if len(args) > 0 {
errors = append(errors, fmt.Sprintf(format, args))
} else {
errors = append(errors, format)
}
}
if len(errors) != 1 {
t.Errorf("excepted one error, actual %v", len(errors))
}
}
Run Code Online (Sandbox Code Playgroud)
我会使用非常方便的bouk/monkey包(这里还有stretchr/testify)。
func TestGoodby(t *testing.T) {
wantMsg := "Goodbye!"
fakeLogFatal := func(msg ...interface{}) {
assert.Equal(t, wantMsg, msg[0])
panic("log.Fatal called")
}
patch := monkey.Patch(log.Fatal, fakeLogFatal)
defer patch.Unpatch()
assert.PanicsWithValue(t, "log.Fatal called", goodbye, "log.Fatal was not called")
}
Run Code Online (Sandbox Code Playgroud)
我建议在走这条路线之前阅读使用 bouk/monkey的注意事项。
虽然可以测试包含log.Fatal的代码,但不建议这样做.特别是,您无法以-cover标志所支持的方式测试该代码go test.
相反,建议您更改代码以返回错误,而不是调用log.Fatal.在顺序函数中,您可以添加额外的返回值,并且在goroutine中,您可以在类型的通道chan error(或包含类型错误的字段的某种结构类型)上传递错误.
一旦进行了更改,您的代码将更容易阅读,更容易测试,并且它将更加可移植(现在除了命令行工具之外,您还可以在服务器程序中使用它).
如果您有log.Println电话我还建议将自定义记录器作为字段传递给接收器.这样您就可以登录到自定义记录器,您可以将其设置为服务器的stderr或stdout,以及用于测试的noop记录器(因此您不会在测试中获得大量不必要的输出).该log软件包支持自定义记录器,因此无需编写自己的记录器或导入第三方软件包.
| 归档时间: |
|
| 查看次数: |
11974 次 |
| 最近记录: |