我想测试一个私有方法 – 我的设计有问题吗?

所以我对软件测试非常陌生,我正在考虑为我的一个应用程序添加几个测试。 我有一个公共方法addKeywords(),它沿途调用私有方法removeInvalidOperations()。 这种私有方法调用外部API并且是大约50行代码。 我认为这是一个有点复杂的方法,我想通过调用addKeyword()方法来测试它,而不必这样做。 但这似乎不可能(至少不是JUnit)。

我所看到的信息表明,测试私有方法的愿望可能是代码味道。 有些人认为这可能表明这应该被重构为一个单独的类并公之于众。 此外,还有一些建议是,如果您确实需要,则可以对生产代码进行编辑,例如更改私有方法的可见性。

我真的不明白为什么我当前的代码设计有问题,但也不喜欢编辑我的生产代码以满足我的测试需求的想法。

正如我所说 – 我对测试很新,所以任何帮助都非常感谢。 另外,如果有任何进一步的信息,我可以告诉我,以帮助解答。

我建议重构一下。

我所看到的信息表明,测试私有方法的愿望可能是代码味道。 有些人认为这可能表明这应该被重构为一个单独的类并公之于众。

你已经在自己的问题中涵盖了支持和反对它的各种原因,你似乎很清楚这些论点。 但是你有一个看似相当复杂的方法并且涉及一个外部API。 这值得自己测试。 removeInvalidOperations()仍然可以是它所在类的私有方法,但它基本上会委托给另一个依赖项。

 class YourClass { private OperationRemover remover; public void addKeywords() { // whatever removeInvalidOperations(); } private void removeInvalidOperations() { remover.remove(); } } 

这为您提供了在某些时候能够替换此依赖项的额外好处,包括能够在不实际放置外部API调用的情况下测试您的addKeywords()方法,这将使测试该方法更容易。 例如, OperationRemover可以是一个接口,出于测试目的,您只需传入一个存根而不是生产中使用的具体版本。 至于具体版本,您可以独立于现有类的内容编写测试。

我真的不明白为什么我当前的代码设计有问题,但也不喜欢编辑我的生产代码以满足我的测试需求的想法。

更易于测试是一项附带好处。 再看看它:你实际做的是使代码松散耦合和可扩展。 上面,我们将调用外部API与可能需要使用结果的代码分开。 外部API可能会发生变化。 您可能会从一个服务转到另一个服务,但使用该结果的代码不必关心。 该类可以保持不变,只有实际调用的类需要修改(或替换)。

现实世界的例子:这一年是2007年,你在美国一家大型金融中心的银行工作。 您的应用程序需要使用帐户信息。 您的代码可以访问银行内部的某种Web服务,并以所需的forms获取所需的信息,然后继续处理它。 2008年,美国金融业崩溃,你的银行(处于崩溃边缘)被另一家银行吞并。 您的应用程序可以免除,除非您现在必须联系到尚存的银行中已存在的其他API以从中获取帐户信息。 消费此帐户信息的代码是否需要更改? 不必要。 它与以前的帐户信息相同,只是来自不同的来源。 不,所有需要改变的是调用API的实现。 消费代码永远不必知道。

这种松散耦合也促进和促进测试的事实是一个奖励。

如果它是private ,它不能被视为应用程序API的一部分,所以测试它确实是代码味道 – 当测试中断时,是否可以?

unit testing应该是面向function的 ,而不是面向代码的 。 您测试function单元,而不是代码单元。

无论哲学如何,实现之外的类都无法在不破坏JVM的情况下访问私有方法,因此您运气不好 – 您必须更改方法的可见性,使unit testing类扩展的protected测试API,或者通过调用使用它的公共方法间接测试函数。

通常您不想测试私有方法,但也有例外。

如果出现以下情况,您可能会尝试测试私有方法:

  1. 您没有仔细考虑如何通过调用现有的公共方法间接测试私有方法。

  2. 你class级的API太不灵活了。 公共方法需要更多参数,或者某些私有方法需要公开。

  3. 你的类的API足够灵活,但在公共方法下面,它有一些相当复杂的私有方法。

根据您的问题,您可能处于任何一种情况。

对于(1),显然你应该首先尝试使用现有的公共方法来测试私有方法。

对于(2)和(3),unit testing不会告诉你你处于哪种情况。你需要做的是编写一些示例代码。 正如Josh Bloch建议的那样 ,为您的API编写一些用例。 您的API应该是满足您的用例所需的最小公共方法集。

(3)是可以测试私有方法的情况。 有各种各样的技巧 。 对于生产代码,这些比将方法暴露给API用户(公开)更好,这样您就可以测试它。 或者将相关function拆分为2个类,以便您可以对其进行测试。

你可以从信息隐藏的角度思考,而不是用“代码气味”来思考,这是不精确和主观的。 不应在您的公共API中公开可能更改的设计决策。 优选地,可能改变的设计决策也不应暴露于您的unit testing – 这就是人们建议不要测试私有方法的原因。

但是如果你真的认为对你的私有方法进行unit testing是很重要的,如果你不能通过公共方法充分地做到这一点,那么就不要牺牲代码的正确性! 测试私有方法。 最糟糕的情况是您的测试代码更加混乱,并且您必须在私有方法更改时重写测试。

如果你不想调用addKeywords() ,也许你应该只添加另一个公共方法testRemoveInvalidOperations()testRemoveInvalidOperations()调用私有的removeInvalidOperations() 。 您可以在以后删除测试。