如何在Golang中实现100%的代码覆盖率?

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

How to get 100% code coverage in Golang?

问题

我无法在Golang中测试致命错误(Fatals),因此无法达到100%的代码覆盖率。

我找到了一些问答,包括这个,但是答案相互矛盾,让我感到困惑。一方面,可以检查Golang中的代码覆盖率。另一方面,有人主张忽略对log.Fatal(err)等的测试,导致代码覆盖率低于100%


尝试

作为一种解决方法,我将所有的log.Fatal替换为panic,并且借助这个答案,我能够测试所有的panic,并实现100%的代码覆盖率。


问题

虽然我能够达到100%的代码覆盖率,但我并不满意,因为我基本上是滥用panic来达到100%的代码覆盖率。根据这个答案panic被用于:

> 当程序或其部分达到无法恢复的状态时

根据这个定义,我的代码中有多个片段可能会引发panic,而应该使用log.Fatal

英文:

I cannot get 100% code coverage as I cannot test Fatals in Golang.

如何在Golang中实现100%的代码覆盖率?

I have found some Q&As including this one, but I am lost as the answers to the posts are contradictory. On the one hand it is possible to check the code coverage in Golang. On the other hand some advocate to ignore the testing of e.g. log.Fatal(err), resulting in a code coverage of less than 100%.


Attempts

As a workaround I replaced all log.Fatal by panic and thanks to this answer I am able to test all the panics and to achieve 100% code coverage.


Problem

Although I am able to get 100% code coverage I am not happy as I am basically misusing panic to get 100% code coverage. According to this answer a panic is used:

> when the program, or its part, has reached an unrecoverable state

Based on this definition there are multiple snippets in my code that can throw a panic, while a log.Fatal should be used.

答案1

得分: 8

由于这个原因,我发现除了主函数之外的所有函数和包都返回错误而不是直接调用log.Fatal是很有用的。然后,主函数可以决定在出现错误时是否退出。不过,试图在任何情况下都获得100%的测试覆盖率可能会在很多情况下带来递减的回报,所以调用log.Fatal可能也是可以接受的。

英文:

For this reason I find it useful for all functions and packages besides main to return errors rather than call log.Fatal directly. Then it can be main's decision to exit or not on errors. Trying to get 100% test coverage no matter what may give diminishing returns in a lot of cases though, so it may also be ok to call it good enough.

答案2

得分: 4

我可以建议的一个技巧是,不要直接调用log.Fatal,而是创建一个具有相同签名的自定义的fatal函数:

在你的包中的任何地方,可以定义一个未导出的fatal变量,类型为func(...interface{}),并将其初始化为log.Fatal

var fatal func(...interface{}) = log.Fatal

这样,其他包就无法设置或使用这个变量。然后,在你的测试代码中,你可以将其替换为:

fatal = func(v ...interface{}) {
    panic(fmt.Sprint(v...))
}

或者你可以根据需要进行其他操作。

当我需要测试time.Now或类似的东西时,我经常使用这种技巧。

英文:

One trick I can suggest is instead of calling log.Fatal, make your own fatal func with the same signature:

var fatal func(...interface{}) = log.Fatal

anywhere in your package. It can be unexported so other packages cannot set or use it. Then in your test you can replace it with:

fatal = func(v ...interface){
    panic(fmt.Sprint(v...))
}

or whatever you want to do.

I use this kind of trick when I need to test time.Now or something of this sort.

huangapple
  • 本文由 发表于 2015年11月23日 22:21:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/33873305.html
匿名

发表评论

匿名网友

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

确定