所以我对软件测试非常陌生,我正在考虑为我的一个应用程序添加几个测试。我有一个公共方法addKeywords(),它沿途调用私有方法removeInvalidOperations()。这种私有方法调用外部API,并且有大约50行代码。我认为这是一个有点复杂的方法,我想通过调用addKeyword()方法来测试它,而不必这样做。但这似乎不可能(至少不是JUnit)。
我所看到的信息表明,测试私有方法的愿望可能是代码味道。有些人认为这可能表明这应该被重构为一个单独的类并公之于众。此外,还有一些建议,如果您确实需要,则可以对您的生产代码进行编辑,例如:更改私有方法的可见性。
我真的不明白为什么我的当前代码设计有问题,但也不喜欢编辑我的生产代码以满足我的测试需求的想法。
正如我所说 - 我对测试很陌生,所以非常感谢任何帮助。另外,如果我能提供任何进一步的信息以帮助解答,请告诉我。
答案 0 :(得分:14)
我建议重构一下。
我所看到的信息表明了测试的愿望 私人方法可能是代码气味。有人建议 这可能表明这应该重构为一个单独的类 并公之于众。
你已经在自己的问题中涵盖了支持和反对它的各种原因,你似乎很清楚这些论点。但是你有一个看似相当复杂的方法,并涉及一个外部API。 这值得自己测试。 removeInvalidOperations()
仍然可以是它所在类的私有方法,但它基本上会委托给另一个依赖。
class YourClass
{
private OperationRemover remover;
public void addKeywords() {
// whatever
removeInvalidOperations();
}
private void removeInvalidOperations() {
remover.remove();
}
}
这为您提供了在某些时候能够替换此依赖项的额外好处,包括能够在不实际放置外部API调用的情况下测试您的addKeywords()
方法,这将使测试该方法更容易。例如,OperationRemover
可以是一个接口,出于测试目的,您只需传入一个存根而不是生产中使用的具体版本。至于您的具体版本,您可以独立于现有类的内容编写测试。
我真的不明白为什么我的当前代码设计有问题, 但也不喜欢编辑我的生产代码以适应我的想法 测试需求。
易于测试是一项附带好处。再看看它:你实际做的是使代码松散耦合和可扩展。上面,我们将调用外部API与可能需要使用结果的代码分开。外部API可能会发生变化。您可能从一个服务转到另一个服务,但使用该结果的代码不必关心。该类可以保持不变,只有实际调用的类需要修改(或替换)。
真实世界的例子:这一年是2007年,你在美国一家大型金融中心的银行工作。您的应用程序需要使用帐户信息。您的代码可以访问银行内部的某种Web服务,并以所需的形式获取所需的信息,然后继续处理它。 2008年,美国金融业崩溃,你的银行(即将崩溃的边缘)被另一家银行吞并。您的应用程序可以免除,除非您现在必须使用已存在的银行中已存在的其他API来从中获取帐户信息。消费此帐户信息的代码是否需要更改?不必要。它与以前的帐户信息相同,只是来自不同的来源。不,所有需要改变的是调用API的实现。消费代码永远不必知道。
这种松耦合也促进和促进测试的事实是一个奖励。
答案 1 :(得分:4)
通常您不想测试私有方法,但也有例外。
如果出现以下情况,您可能会尝试测试私有方法:
您没有仔细考虑过如何测试私有方法 通过调用现有的公共方法间接地。
您班级的API太不灵活了。公共方法需要更多 参数或某些私有方法需要公开。
你班级的API足够灵活,但在公众面前 它有一些相当复杂的私有方法 下方。
根据您的问题,您可能处于任何一种情况。
对于(1),显然你应该首先尝试使用现有的公共方法来测试私有方法。
对于(2)和(3),单元测试不会告诉你你在哪种情况。你需要做的是编写一些示例代码。作为Josh Bloch recommends,为您的API编写一些用例。您的API应该是满足您的用例所需的最小公共方法集。
(3)是可以测试私有方法的情况。有各种tricks for that。对于生产代码,这些比将方法暴露给API用户(使其公开)更好,因此您可以对其进行测试。或者将相关功能拆分为2个类,以便您可以对其进行测试。
你可以用information hiding来思考,而不是用“代码气味”来思考,这是不精确和主观的。不应在您的公共API中公开可能更改的设计决策。优选地,可能改变的设计决策也不应暴露于您的单元测试 - 这就是人们建议不要测试私有方法的原因。
但是如果你真的认为对你的私有方法进行单元测试是很重要的,如果你不能通过公共方法充分地做到这一点,那么就不要牺牲代码的正确性!测试私有方法。最糟糕的情况是您的测试代码更加混乱,并且您必须在私有方法更改时重写测试。
答案 2 :(得分:0)
如果您不想拨打addKeywords()
,或许您应该添加另一个公共方法testRemoveInvalidOperations()
,它只调用私有removeInvalidOperations()
。您可以在以后删除测试。