我已经阅读了这篇关于如何测试私有方法的文章。我通常不测试它们,因为我总是认为只测试将从对象外部调用的公共方法更快。你测试私有方法吗?我应该一直测试它们吗?


当前回答

“我应该测试私有方法吗?”的答案是“有时.......”。通常情况下,您应该针对类的接口进行测试。

其中一个原因是您不需要对一个特性进行双重覆盖。 另一个原因是,如果您更改了私有方法,则必须为它们更新每个测试,即使对象的接口根本没有更改。

这里有一个例子:

class Thing
  def some_string
    one + two
  end

  private 

  def one
    'aaaa'
  end

  def two
    'bbbb'
  end

end


class RefactoredThing
def some_string
    one + one_a + two + two_b
  end

  private 

  def one
    'aa'
  end

  def one_a
    'aa'
  end

  def two
    'bb'
  end

  def two_b
    'bb'
  end
end

在RefactoredThing中,你现在有5个测试,其中2个你必须为重构而更新,但你的对象的功能实际上没有改变。所以让我们假设事情比这更复杂,你有一些方法来定义输出的顺序,比如:

def some_string_positioner
  if some case
  elsif other case
  elsif other case
  elsif other case
  else one more case
  end
end

这不应该由外部用户来运行,但是您的封装类可能太笨重了,无法一遍又一遍地运行这么多逻辑。在这种情况下,您可能更愿意将其提取到一个单独的类中,为该类提供一个接口并对其进行测试。

最后,假设你的主对象非常重,方法非常小你需要确保输出是正确的。你会想,“我必须测试这个私有方法!”也许你可以通过传入一些繁重的工作作为初始化参数使你的对象更轻?然后你可以放一些更轻的东西进去测试。

其他回答

当我在我们的项目中越来越多地遵循我们最新的QA建议时,我感觉有必要测试私有函数:

每个函数圈复杂度不超过10。

现在,执行这项政策的副作用是,我的许多非常大的公共职能被划分为许多更集中的,更好地命名为私人职能。 公共功能仍然存在(当然)但本质上被简化为所有那些私人的“子功能”

这实际上很酷,因为调用堆栈现在更容易阅读(而不是一个大函数中的bug,我在一个子子函数中有一个bug,它具有调用堆栈中先前函数的名称,以帮助我理解“我是如何到达那里的”)

然而,现在似乎更容易直接对那些私有函数进行单元测试,而将大型公共函数的测试留给某种需要解决场景的“集成”测试。

这只是我的个人意见。

我从来不理解单元测试的概念,但现在我知道它的目标是什么了。

单元测试不是一个完整的测试。所以,它并不是QA和手动测试的替代品。在这方面,TDD的概念是错误的,因为你不能测试所有的东西,包括私有方法,也包括使用资源的方法(特别是我们无法控制的资源)。TDD的所有质量都是无法实现的。

单元测试更像是一个枢轴测试,你标记一些任意的枢轴,枢轴的结果应该保持不变。

如果您正在开发测试驱动(TDD),您将测试您的私有方法。

我认为单元测试是用来测试公共方法的。您的公共方法使用您的私有方法,因此它们也间接地接受测试。

我已经为这个问题苦恼了一段时间,尤其是在尝试TDD的时候。

我曾经看到过两篇文章,我认为它们在TDD的情况下已经足够彻底地解决了这个问题。

测试私有方法,TDD和测试驱动重构 测试驱动开发不是测试


总而言之:

当使用测试驱动开发(设计)技术时,私有方法应该只在重构已经工作和测试过的代码的过程中出现。 根据这个过程的本质,任何从经过彻底测试的功能中提取出来的简单实现功能都将是自我测试的(即间接测试覆盖率)。

对我来说,在编码的开始部分,大多数方法都是高级函数,因为它们封装/描述了设计。

因此,这些方法将是公开的,并且测试它们将非常容易。

私有方法将在一切正常工作后出现,并且为了可读性和清洁度我们正在进行重构。