公开私有方法以进行单元测试...好主意?

2022-08-31 05:00:24

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


我偶尔会发现自己需要公开类中的私有方法,以便为它编写一些单元测试。

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

其他人会发现自己这样做,因为我真的不喜欢这样做吗?我个人认为奖金超过了公开一种方法的问题,这种方法并没有真正提供课堂以外的任何服务......

更新

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

然而,我可以看到每个人都指出,它永远不应该真正发生。当仔细考虑这个问题时,我认为更改代码以适应测试是一个坏主意 - 毕竟我认为测试在某种程度上是一种支持工具,如果你愿意的话,将系统更改为“支持支持工具”,这是公然的坏做法。


答案 1

注意:
这个答案最初是为一个问题发布的,即单元测试本身是否是通过getters公开私有实例变量的好理由?这个问题被合并到这个问题中,所以它可能有点特定于那里呈现的用例。

作为一般声明,我通常都支持重构“生产”代码,使其更易于测试。但是,我不认为这将是一个好的电话。一个好的单元测试(通常)不应该关心类的实现细节,而只关心它的可见行为。您可以测试该类在调用 或 后按预期顺序返回页面,而不是向测试公开内部堆栈。first()last()

例如,请考虑以下伪代码:

public class NavigationTest {
    private Navigation nav;

    @Before
    public void setUp() {
        // Set up nav so the order is page1->page2->page3 and
        // we've moved back to page2
        nav = ...;
    }

    @Test
    public void testFirst() {
        nav.first();

        assertEquals("page1", nav.getPage());

        nav.next();
        assertEquals("page2", nav.getPage());

        nav.next();
        assertEquals("page3", nav.getPage());
    }

    @Test
    public void testLast() {
        nav.last();

        assertEquals("page3", nav.getPage());

        nav.previous();
        assertEquals("page2", nav.getPage());

        nav.previous();
        assertEquals("page1", nav.getPage());
    }
}

答案 2

就个人而言,我宁愿使用公共API进行单元测试,我当然不会为了让测试变得容易而公开私有方法。

如果你真的想单独测试私有方法,在Java中,你可以使用Easymock / Powermock来允许你这样做。

你必须对此持务实态度,你也应该意识到为什么事情很难测试的原因。

'听测试 - 如果很难测试,这是否告诉你一些关于你的设计的事情?您能否重构到此方法的测试是微不足道的,并且可以通过公共 API 进行测试轻松覆盖?

以下是Michael Feathers在“有效使用遗留代码”中所说的话"

“许多人花了很多时间试图弄清楚如何解决这个问题......真正的答案是,如果你有测试私有方法的冲动,那么该方法不应该是私有的;如果公开该方法困扰您,很可能是因为它是单独责任的一部分;它应该在另一个类上。[有效使用遗留代码(2005)由M. Feathers]


推荐