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


当前回答

我倾向于遵循Dave Thomas和Andy Hunt在他们的书《实用单元测试》中的建议:

一般来说,为了不破坏任何封装 测试(或者就像妈妈常说的,“不要暴露你的私处!”)。大多数 此时,您应该能够通过执行类的 公共方法。如果隐藏了重要的功能 在私人或受保护访问的背后,这可能是一个警告信号 还有一群人在里面挣扎着想出来。

但有时我无法阻止自己测试私有方法,因为它给了我一种安全感,我正在构建一个完全健壮的程序。

其他回答

我倾向于遵循Dave Thomas和Andy Hunt在他们的书《实用单元测试》中的建议:

一般来说,为了不破坏任何封装 测试(或者就像妈妈常说的,“不要暴露你的私处!”)。大多数 此时,您应该能够通过执行类的 公共方法。如果隐藏了重要的功能 在私人或受保护访问的背后,这可能是一个警告信号 还有一群人在里面挣扎着想出来。

但有时我无法阻止自己测试私有方法,因为它给了我一种安全感,我正在构建一个完全健壮的程序。

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

考虑一下下面略显做作的例子。假设我们想公开一个函数,该函数接受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.

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

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

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

你也可以让你的方法包私有,即默认,你应该能够单元测试它,除非它被要求是私有的。

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

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

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