单元测试,私有方法和隐藏抽象

时间:2020-02-21 17:53:30

标签: unit-testing private-methods

我正在阅读有关单元测试的内容,以进一步了解它。

似乎测试私有方法不应该是一般规则,而只是一些例外。我找到了这篇文章,其中对此进行了解释:https://enterprisecraftsmanship.com/posts/unit-testing-private-methods/

这里说到,如果私有方法很复杂,那么一种选择是创建一个公共类并在此处实现该方法,以便对其进行测试。

这是我的疑问。

不测试私有方法的原因是,建议仅测试客户端可以从库中使用的内容。

使用私有方法的原因是不要让客户端知道或了解内部实现的详细信息,因此最好使客户端的库尽可能简单。

但是,如果为了测试私有方法,我创建了一个新的公共类,则将该方法放到现在是公共的地方,我是否没有向客户提供有关实现的详细信息?实际上,不是将public方法声明为public方法,而是创建了一个public类来放置public方法。

所以我想我误会了一些东西,但是我不知道是什么。

在此问题的答案之一中:How do you unit test private methods?,据说一种选择是也将私有方法传递给公共类,但是并不能解释更多(我想答案可能是更长)。

谢谢。

2 个答案:

答案 0 :(得分:2)

但是,如果为了测试私有方法,我创建了一个新的公共类,则将该方法放到现在是公共的地方,我是否没有向客户提供有关实现的详细信息?

这里的窍门是不实际上公开此内容。确切的操作方式取决于语言/生态系统,但是通常来说,您将尝试以一种最终用户无法(轻松)访问实现细节的方式来发布代码。

例如,在C ++中,您可以使用私有头文件来公开您的库不附带的功能(如果接口头文件中未包含这些功能,则不成问题)。 Java具有其“拼图”模块系统。但是即使这样,如果不能机械地强制执行它,您仍然可以通过社会地强制执行它,方法是在最终用户不使用时使用包和类名之类的内容非常清楚应该用东西例如,如果您未使用Java的模块系统,则仍可以在名为lib.foo的程序包中获取有关程序包lib.foo.implementation_details的实现详细信息,类似于在Smalltalk这样的语言中却没有私有方法完全可以,您仍然可以给您的方法起个类似private_foo的名称,这很清楚它们不是供外部用户使用的。

当然,机械强制执行效果更好,但是请注意,并非总是可以选择的。即使它不可用,私有与公共,接口与实现的原理仍然适用,您只需要在确保人们真正遵守这些事情上更有创意即可。< / p>

答案 1 :(得分:1)

不测试私有方法的原因是,建议仅测试客户端可以从库中使用的内容。

有很多人解释单元测试的“目标”,但实际上,他们在进行单元测试时描述的是他们的目标。单元测试被应用于许多不同的领域和环境,从玩具项目开始,直到在核工厂,飞机等安全相关的软件中结束。

换句话说,有很多开发的软件可以满足上述建议。但是,您可以应用除此以外的单元测试方法。如果您不想从一开始就受限于什么程度的单元测试,最好以以下方式查看它:总体测试以及单元测试的主要目标之一是找到错误(请参阅Myers,Badgett,Sandler:软件测试的技巧,或Beizer:软件测试技术,以及许多其他错误)。

将单元测试看作是发现错误,这是理所当然的,然后您可能还需要测试实现细节:错误在实现中-相同功能的不同实现具有不同的错误。使用一个简单的斐波那契函数:可以将其实现为递归函数,迭代函数,闭合表达式(Moivre / Binet),使用手写查找表,使用自动生成的查找表等。这些实现中的每一个,可能的错误集都会有很大的不同。

另一个例子是排序:有很多排序函数,从功能的角度来看,它们执行相同的操作,甚至有许多具有相同的用户界面。就测试而言,IntroSort算法非常有趣,因为它实现了快速排序,但是当它意识到运行为退化排序时,就会退回到另一个算法(通常是堆排序)。测试IntroSort意味着还要创建这样的退化数据集,以强制算法进入堆排序,只是确保可以找到堆排序部分中的潜在错误。仅从公共接口来看,您永远不会想出这样的测试用例(至少那是一个巧合)。

到目前为止,总结:测试实施细节绝不是一个坏习惯。这是有代价的:在实现更改时,用于实现细节的测试肯定会更容易失效或变得无用。因此,查找更多错误是否比节省测试维护工作更重要,取决于您的项目。

关于使私有功能可用于测试但仍未使其成为“官方”公共接口的一部分的可能性:@Cubic很好地解释了a)public在可见性的技术意义上的区别给定编程语言的规则,以及b)属于“官方”且有文件证明的公共API。

相关问题