标准库错误的覆盖测试

Posted

技术标签:

【中文标题】标准库错误的覆盖测试【英文标题】:Coverage test for standard library errors 【发布时间】:2018-09-04 23:52:21 【问题描述】:

我一直在尝试了解 Go 的内置测试框架并获得适当的测试覆盖率。

在我正在测试的其中一个文件中,我只获得了约 87% 的覆盖率:

coverage: 87.5% of statements

下面是测试中涉及的一段代码:

// Check that the working directory is set
if *strctFlags.PtrWorkDir == "" 

// if the working directory is empty, set it to the current directory
strTemp, err := os.Getwd()
if err != nil 
    return "", errors.New("Could not get current working directory")


*strctFlags.PtrWorkDir = strTemp

 else if stat, err := os.Stat(*strctFlags.PtrWorkDir); err != nil ||
!stat.IsDir() 

    // Existence check of the work dir
    return "", errors.New("Specified directory \"" + *strctFlags.PtrWorkDir + "\" could not be found or was not a directory")


*strctFlags.PtrWorkDir, err = filepath.Abs(*strctFlags.PtrWorkDir)
if err != nil 
    return "", errors.New("Could not determine absolute filepath: " + err.Error())

根据 .out 文件,测试中未涵盖的部分是“if err != nil ”块,这将是标准库调用返回的错误。

虽然我认为除非出现硬件故障,否则标准库传递错误的可能性很小,但我认为最好知道错误在应用程序中得到了正确处理。此外,据我了解,检查返回的错误是惯用的 Go,因此我认为能够正确测试错误处理会很好。

人们如何处理上述情况的测试错误?是否有可能获得 100% 的覆盖率,或者我做错了什么或结构不正确?还是人们跳过测试这些条件?

【问题讨论】:

Some people skip them.。如果您出于某种原因必须拥有 100% 的测试覆盖率,那么您可能应该模拟/存根所有 stdlib 调用。 Go 标准库包是否具有 100% 的测试覆盖率?所有其他外部软件包是否具有 100% 的测试覆盖率?操作系统调用是否具有 100% 的测试覆盖率。硬件是否具有 100% 的测试覆盖率。是否测试了所有可能的整数和浮点算术?这需要多长时间?错误发生:Intel Pentium FDIV bug。等等。 100% 覆盖率测试是不可能的。 对于任何重要的代码(即任何使用 I/O 的代码),100% 的测试覆盖率是字面上的不可能,因为字面上有 无限代码执行路径的数量(即使假设相同的硬件等)。因此,以 100% 的覆盖率为目标是徒劳的。尽管通常可以让测试覆盖率工具(如 Go 提供的工具)报告 100%。但这不是很有意义,所以这不是一个有价值的目标。 为什么需要 100% 的覆盖率? @JoelCornett - 听起来不是很有必要,我在问是否有一种通用的方法可以以一种白痴的方式为 Go 测试这种场景,以及人们通常如何处理这种情况。 【参考方案1】:

正如@flimzy 在他的回答中解释的那样,以 100% 的覆盖率为目标并不好,而是以有用的测试覆盖率为目标。

虽然您可以像这样对代码稍作修改来测试系统调用

package foo

// Get Working directory function
var osGetWd = os.Getwd

func GetWorkingDirectory() (string,error)
    strTemp, err := osGetWd() // Using the function defined above
    if err != nil 
       return "", errors.New("Could not get current working directory")
    return strTemp,nil

在测试时

package foo

func TestGetWdError() 
    // Mocked function for os.Getwd
    myGetWd := func() (string,error) 
      myErr := errors.New("Simulated error")
      return "",myErr
    

    // Update the var to this mocked function
    osGetWd = myGetWd

   // This will return error
   val,err := GetWorkingDirectory()

这将帮助您实现 100% 的覆盖率

【讨论】:

看起来这就是我要找的东西!我知道 100% 的测试覆盖率并不是万无一失的,并且很欣赏这种观点背后的理念,但同时我觉得我已经了解了该语言的工作原理(我没有遇到过我之前可以通过这种方式将变量分配给函数...)【参考方案2】:

在许多非硬件故障场景中,大多数标准库函数都可能会失败。您是否愿意测试这些是另一个问题。例如,对于os.Getwd(),如果工作目录不存在,我可能会认为调用会失败(您可以努力测试这个场景)。

可能更有用(通常是更好的测试方法)是模拟这些调用,以便您可以在测试期间触发错误,以便您可以测试错误案例代码。

但是,出于对代码的热爱,请不要以 100% 的测试覆盖率为目标。瞄准有用的测试覆盖率。可以使工具报告 100% 的覆盖率而不覆盖有用的案例,并且可以覆盖有用的案例而不使工具报告 100%。

但是真的 100% 的覆盖率在大多数程序中是不可能的(即使是简单的“Hello World!”)。所以不要瞄准它。

【讨论】:

我有点同意,但这不是覆盖率计算解决方案的缺点吗?我的意思是,如果我覆盖了 100% 的逻辑,那么覆盖率报告工具不应该理解它,而不仅仅是老生常谈地计算代码行数吗? 缺点是假装任何覆盖工具的数字意味着更多。在现代计算机上,在任何现代程序中覆盖“100% 的逻辑”实际上是不可能的。 程序员可能理解,但很难向项目管理人员甚至客户解释(如果他们关心这些指标的话)。 现实很难向项目经理解释这一事实不是工具可以解决的。

以上是关于标准库错误的覆盖测试的主要内容,如果未能解决你的问题,请参考以下文章

Python标准库:HTTP客户端库urllib3

Standard C 语言标准函数库介绍

STL标准库 & 范型编程学习笔记:容器的结构分类测试

STL标准库 & 范型编程学习笔记:容器的结构分类测试

STL标准库 & 范型编程学习笔记:分配器之测试

STL标准库 & 范型编程学习笔记:分配器之测试