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


当前回答

是的,您应该在任何可能的地方测试私有方法。为什么?避免不必要的测试用例状态空间爆炸,最终只是在相同的输入上隐式地重复测试相同的私有函数。让我们用一个例子来解释为什么。

考虑一下下面略显做作的例子。假设我们想公开一个函数,该函数接受3个整数,当且仅当这3个整数都是素数时返回true。我们可以这样实现它:

public bool allPrime(int a, int b, int c)
{
  return andAll(isPrime(a), isPrime(b), isPrime(c))
}

private bool andAll(bool... boolArray)
{
  foreach (bool b in boolArray)
  {
    if(b == false) return false;
  }
  return true;
}

private bool isPrime(int x){
  //Implementation to go here. Sorry if you were expecting a prime sieve.
}

现在,如果我们采取严格的方法,只测试公共函数,我们只允许测试allPrime,而不允许测试isPrime或andAll。

作为测试人员,我们可能对每个参数的五种可能性感兴趣:< 0,= 0,= 1,质数> 1,而不是质数> 1。但为了彻底,我们还必须看看每个参数的组合是如何发挥作用的。根据我们的直觉,我们需要5*5*5 = 125个测试用例来彻底测试这个函数。

On the other hand, if we were allowed to test the private functions, we could cover as much ground with fewer test cases. We'd need only 5 test cases to test isPrime to the same level as our previous intuition. And by the small scope hypothesis proposed by Daniel Jackson, we'd only need to test the andAll function up to a small length e.g. 3 or 4. Which would be at most 16 more tests. So 21 tests in total. Instead of 125. Of course, we probably would want to run a few tests on allPrime, but we wouldn't feel so obliged to cover exhaustively all 125 combinations of input scenarios we said we cared about. Just a few happy paths.

当然,这是一个虚构的例子,但为了清晰地演示,这是必要的。这种模式可以扩展到真实的软件中。私有函数通常是最低级别的构建块,因此经常组合在一起以产生更高级别的逻辑。也就是说,在较高的层次上,由于不同的组合,我们对较低层次的东西有更多的重复。

其他回答

不,你不应该测试私有方法,为什么?此外,流行的mock框架(如Mockito)不支持测试私有方法。

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

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

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


总而言之:

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

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

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

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

我不是这方面的专家,但是单元测试应该测试行为,而不是实现。私有方法严格来说是实现的一部分,所以不应该测试IMHO。

我认为最好只测试对象的公共接口。从外部世界的角度来看,只有公共接口的行为是重要的,这是您的单元测试应该指向的方向。

一旦你为一个对象编写了一些可靠的单元测试,你就不希望因为接口背后的实现改变了而不得不回去修改那些测试。在这种情况下,您已经破坏了单元测试的一致性。

我看到很多人都有同样的想法:在公共层面上进行测试。但这不正是我们的QA团队所做的吗?他们测试输入和预期输出。如果作为开发人员,我们只测试公共方法,那么我们只是在重做QA的工作,而不是通过“单元测试”来增加任何价值。