如何测试中,含有log.Fatal去功能()
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何测试中,含有log.Fatal去功能()相关的知识,希望对你有一定的参考价值。
我说,我有以下代码打印一些日志消息。我怎么会去测试正确的消息已经被记录?作为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()
这里是假设的测试:
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)
这类似于“How to test os.Exit()
scenarios in 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)
(在这里,我的“退出”功能是一个空的这什么都不做)
我曾尝试使用下面的代码来测试我的功能。在xxx.go:
var logFatalf = log.Fatalf
if err != nil
logFatalf("failed to init launcher, err:%v", err)
而在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))
虽然它可以测试包含log.Fatal代码,所以不推荐。特别是,你不能在由上-cover
的go test
标志支持的方式测试代码。
相反,它建议你改变你的代码,改为返回调用log.Fatal的错误。在顺序功能,可以添加额外的返回值,并在一个够程可以类型chan error
的信道(或包含错误类型的领域中的一些结构类型)上传递一个错误。
一旦做出更改您的代码会更容易阅读,更容易测试,这将是更便携(现在除了可以用它在服务器程序的命令行工具)。
如果你有log.Println
调用我还建议通过自定义记录器作为接收器的领域。这样,你就可以登录到自定义记录器,你可以设置为标准错误或标准输出为一个服务器,并测试一个空操作记录器(这样你就不会得到你的测试一堆不必要的输出)。该log
包支持自定义记录程序,所以没有必要写你自己的或导入第三方软件包这一点。
如果您使用logrus,还有现在是时候从this commit推出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)
我(与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")
我建议阅读caveats to using bouk/monkey才去这条路线。
那里曾经是这里的答案我提及的,看起来像它删除了。这是我见过的,你可能已经通过测试,而不需要修改的依赖或以其他方式接触代码应该致命的唯一的一个。
我同意其他的答案,这通常是不恰当的测试。通常你应该重写被测代码返回一个错误,测试观察非零误差后返回的错误预期,并且致命处于较高的水平范围。
要测试的正确的消息已经被记录下来,你会检查内部流程的cmd.Stdout
的OP的问题。
https://play.golang.org/p/J8aiO9_NoYS
func TestFooFatals(t *testing.T)
fmt.Println("TestFooFatals")
outer := os.Getenv("FATAL_TESTING") == ""
if outer
fmt.Println("Outer process: Spawning inner `go test` process, looking for failure from fatal")
cmd := exec.Command(os.Args[0], "-test.run=TestFooFatals")
cmd.Env = append(os.Environ(), "FATAL_TESTING=1")
// cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
err := cmd.Run()
fmt.Printf("Outer process: Inner process returned %v\n", err)
if e, ok := err.(*exec.ExitError); ok && !e.Success()
// fmt.Println("Success: inner process returned 1, passing test")
return
t.Fatalf("Failure: inner function returned %v, want exit status 1", err)
else
// We're in the spawned process.
// Do something that should fatal so this test fails.
foo()
// should fatal every time
func foo()
log.Printf("oh my goodness, i see %q\n", os.Getenv("FATAL_TESTING"))
// log.Fatal("oh my gosh")
你不能和你不应该。这个“你必须‘测试’每一条线路” -attitude很奇怪,尤其是对终端条件,这就是log.Fatal是。 (或者只是从外部对其进行测试。)
以上是关于如何测试中,含有log.Fatal去功能()的主要内容,如果未能解决你的问题,请参考以下文章