英文:
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.
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论