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

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


当前回答

今天,我推出了一个Java库来帮助测试私有方法和字段。它的设计考虑到了Android,但它确实可以用于任何Java项目。

如果您有一些带有私有方法、字段或构造函数的代码,可以使用BoundBox。它正是你想要的。下面是一个测试示例,它访问Android活动的两个私有字段来测试它:

@UiThreadTest
public void testCompute() {

    // Given
    boundBoxOfMainActivity = new BoundBoxOfMainActivity(getActivity());

    // When
    boundBoxOfMainActivity.boundBox_getButtonMain().performClick();

    // Then
    assertEquals("42", boundBoxOfMainActivity.boundBox_getTextViewMain().getText());
}

BoundBox使测试私有/受保护的字段、方法和构造函数变得容易。你甚至可以访问被继承隐藏的东西。实际上,BoundBox打破了封装。它会让您通过反射访问所有这些内容,但在编译时会检查所有内容。

它非常适合测试一些遗留代码。小心使用。;)

其他回答

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

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

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

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

私有方法只能在同一类中访问。因此,无法从任何测试类测试目标类的“私有”方法。一种方法是,您可以手动执行单元测试,也可以将方法从“私有”更改为“受保护”。

然后,受保护的方法只能在定义类的同一个包中访问。因此,测试目标类的受保护方法意味着我们需要在与目标类相同的包中定义测试类。

如果以上所有内容都不符合您的要求,请使用反射方式访问私有方法。

在C#中,您可以使用System.Reflection,尽管在Java中我不知道。如果你“觉得你需要对私有方法进行单元测试”,我的猜测是还有其他一些地方是错误的。。。

我会认真考虑用新的眼光重新审视我的建筑。。。

当我的类中有足够复杂的私有方法,以至于我觉得需要直接测试私有方法时,这是一种代码气味:我的类太复杂了。

我解决这些问题的通常方法是梳理出一个包含有趣内容的新类。通常,这个方法及其交互的字段,或者可以将另一个或两个方法提取到一个新类中。

新类将这些方法公开为“public”,因此可以对它们进行单元测试。新的和旧的类现在都比原来的类简单,这对我来说很好(我需要保持简单,否则我会迷路!)。

注意,我并不是建议人们不用大脑就可以创建课程!这里的重点是使用单元测试的力量来帮助您找到好的新类。

请参见下面的示例;

应添加以下导入语句:

import org.powermock.reflect.Whitebox;

现在,您可以直接传递具有私有方法、要调用的方法名和其他参数的对象,如下所示。

Whitebox.invokeMethod(obj, "privateMethod", "param1");