如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?

仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。


当前回答

对于Java,我会使用反射,因为我不喜欢仅仅为了测试而更改对声明方法的包的访问。然而,我通常只测试公共方法,这也应该确保私有方法正常工作。

不能使用反射从所有者类外部获取私有方法,私有修饰符也会影响反射

这不是真的。你当然可以,正如塞姆·卡提卡斯的回答中所提到的。

其他回答

私有方法被公共方法使用。否则,它们就是死代码。这就是为什么要测试公共方法,断言公共方法的预期结果,从而断言它使用的私有方法。

在公共方法上运行单元测试之前,应该通过调试来测试私有方法。

也可以使用测试驱动开发来调试它们,调试单元测试,直到满足所有断言。

我个人认为最好使用TDD创建类;创建公共方法存根,然后使用预先定义的所有断言生成单元测试,这样在编写代码之前就可以确定方法的预期结果。这样,就不会走上使单元测试断言符合结果的错误道路。然后,当所有单元测试通过时,您的类是健壮的并满足要求。

对于Java,我会使用反射,因为我不喜欢仅仅为了测试而更改对声明方法的包的访问。然而,我通常只测试公共方法,这也应该确保私有方法正常工作。

不能使用反射从所有者类外部获取私有方法,私有修饰符也会影响反射

这不是真的。你当然可以,正如塞姆·卡提卡斯的回答中所提到的。

在尝试了Cem Catikkas使用Java反射的解决方案后,我不得不说,他的解决方案比我在这里描述的更优雅。然而,如果您正在寻找使用反射的替代方案,并且能够访问您正在测试的源代码,那么这仍然是一个选项。

测试类的私有方法可能有好处,特别是在测试驱动开发中,您希望在编写任何代码之前设计小型测试。

创建一个可以访问私有成员和方法的测试,可以测试那些只访问公共方法而难以专门针对的代码区域。如果公共方法涉及多个步骤,它可以由多个私有方法组成,然后可以单独测试。

优势:

可以测试到更精细的粒度

缺点:

测试代码必须位于文件作为源代码更难维护与.class输出文件类似,它们必须保持在源代码中声明的相同包中

然而,如果连续测试需要这种方法,这可能是一个信号,表明应该提取私有方法,可以以传统的公共方式进行测试。

下面是一个复杂的例子,说明这是如何工作的:

// Import statements and package declarations

public class ClassToTest
{
    private int decrement(int toDecrement) {
        toDecrement--;
        return toDecrement;
    }

    // Constructor and the rest of the class

    public static class StaticInnerTest extends TestCase
    {
        public StaticInnerTest(){
            super();
        }

        public void testDecrement(){
            int number = 10;
            ClassToTest toTest= new ClassToTest();
            int decremented = toTest.decrement(number);
            assertEquals(9, decremented);
        }

        public static void main(String[] args) {
            junit.textui.TestRunner.run(StaticInnerTest.class);
        }
    }
}

内部类将编译为ClassToTest$StaticInnerTest。

另请参阅:Java提示106:静态内部类以获取乐趣和利润

JUnit.org常见问题解答页面的答案:

但如果你必须。。。如果您使用的是JDK1.3或更高版本,则可以使用反射来颠覆访问控制机制。有关如何使用它的详细信息,请阅读本文。如果您使用的是JDK1.6或更高版本,并且使用@测试时,可以使用Dp4j在测试方法中注入反射。对于有关如何使用它的详细信息,请参阅此测试脚本。

P.S.我是Dp4j的主要贡献者。问我你是否需要帮助。:)

我想分享一条关于测试的规则,这条规则尤其与本主题相关:

我认为你不应该为了更轻松地编写测试。

在其他帖子中有一些建议,说你应该调整原始类以测试私有方法-请先将此警告标记为红色。

如果我们将方法/字段的可访问性更改为包私有或受保护,只是为了让测试可以访问它,那么我们就违背了私有访问指令存在的目的。

当我们想要进行测试驱动的开发时,为什么要有私有字段/方法/类?那么,我们是否应该将所有内容都声明为私有的,甚至是公共的,这样我们就可以不费力地进行测试了-我不这么认为。

从另一个角度来看:测试不应影响生产应用程序的性能和执行。

如果我们仅仅为了更容易的测试而更改生产代码,这可能会在某种程度上影响性能和应用程序的执行。

如果有人开始将私有访问更改为包私有,那么开发人员最终可能会想出其他“巧妙的想法”,向原始类添加更多代码。这会给可读性带来额外的噪音,并会影响应用程序的性能。

随着私有访问更改为限制性较小的访问,我们为开发人员在应用程序的未来开发中滥用新情况提供了可能性。我们不是强迫他/她以正确的方式发展,而是用新的可能性引诱他/她,让他/她有能力在未来做出错误的选择。

当然,这条规则可能会有一些例外,但如果理解清楚,规则是什么,例外是什么?我们需要绝对确定我们知道为什么会引入这种例外。