主持人注:这里已经有39个答案了(有些已经删除了)。在你发表你的答案之前,考虑一下你是否可以为讨论添加一些有意义的东西。你很可能只是在重复别人已经说过的话。


我偶尔发现自己需要将类中的私有方法设为public,只是为了为它编写一些单元测试。

通常这是因为该方法包含类中其他方法之间共享的逻辑,并且单独测试逻辑更整洁,或者另一个原因可能是我想测试同步线程中使用的逻辑,而不必担心线程问题。

其他人发现他们这样做是因为我不喜欢吗?我个人认为,公开一个方法的好处超过了它在类之外没有提供任何服务的问题……

更新

谢谢大家的回答,似乎引起了大家的兴趣。我认为普遍的共识是测试应该通过公共API进行,因为这是使用类的唯一方式,我非常同意这一点。在我上面提到的几个案例中,我会这样做,这是不常见的情况,我认为这样做的好处是值得的。

然而,我可以看到,每个人都指出它不应该真的发生。再仔细想想,我觉得改变你的代码来适应测试是一个坏主意——毕竟我认为测试在某种程度上是一个支持工具,而改变一个系统来“支持一个支持工具”是明显的坏做法。


当前回答

就单元测试而言,你绝对不应该添加更多的方法;我相信你最好做一个关于你的第一个()方法的测试用例,它将在每次测试之前被调用;然后,您可以多次调用- next(), previous()和last(),以查看结果是否符合您的期望。 我猜如果你不给你的类添加更多的方法(只是为了测试的目的),你会坚持测试的“黑盒”原则;

其他回答

一些很棒的答案。我没有看到提到的一件事是,在测试驱动开发(TDD)中,私有方法是在重构阶段创建的(关于重构模式的示例,请参阅Extract Method),因此应该已经具有必要的测试覆盖率。如果做得正确(当然,当涉及到正确性时,您将得到各种各样的意见),您应该不必担心必须将私有方法设为公共,以便您可以测试它。

许多答案建议只测试公共接口,但恕我直言,这是不现实的——如果一个方法执行的操作需要5个步骤,那么您将希望分别测试这5个步骤,而不是一起测试。这需要测试所有五个方法,否则它们(除了测试之外)可能是私有的。

测试“私有”方法的通常方法是给每个类一个自己的接口,并将“私有”方法设为公共的,但不将它们包含在接口中。这样,它们仍然可以被测试,但不会使界面膨胀。

是的,这将导致文件和类膨胀。

是的,这确实使公共和私有说明符变得多余。

是啊,这真让人头疼。

不幸的是,这是我们为使代码可测试而做出的众多牺牲之一。也许未来的语言(或者甚至是c# /Java的未来版本)将具有使类和模块可测试性更加方便的特性;但与此同时,我们得跳过这些障碍。


There are some who would argue that each of those steps should be its own class, but I disagree - if they all share state, there is no reason to create five separate classes where five methods would do. Even worse, this results in file- and class-bloat. Plus, it infects the public API of your module - all those classes must necessarily be public if you want to test them from another module (either that, or include the test code in the same module, which means shipping the test code with your product).

私有方法通常用作“助手”方法。因此,它们只返回基本值,从不操作对象的特定实例。

如果您想测试它们,您有几个选项。

使用反射 给这些方法包访问权

或者,如果helper方法是一个足够好的新类候选,您可以使用它作为公共方法创建一个新类。

这里有一篇很好的文章。

如果需要,使用反射来访问私有变量。

但实际上,您并不关心类的内部状态,您只想测试公共方法是否在您可以预期的情况下返回您所期望的内容。

正如其他人所说,单元测试私有方法有点可疑;单元测试公共接口,而不是私有实现细节。

也就是说,当我想对c#中私有的东西进行单元测试时,我使用的技术是将可访问性保护从私有降级为内部,然后使用InternalsVisibleTo将单元测试程序集标记为友程序集。然后,单元测试程序集将被允许将内部组件视为公共的,但您不必担心会意外地增加公共表面区域。