Java中的存根私有方法

Java中的存根私有方法,java,unit-testing,Java,Unit Testing,我正在测试一个函数,它接受几个参数,并根据它们的值调用不同的私有方法 我想检查函数是否总是调用正确的私有方法 因为我知道私有方法将要做什么,所以我可以检查最终结果,但是如果能够直接检查是否调用了正确的函数,会更方便,因为我已经测试了私有方法 有没有办法用存根替换privae方法?您可以检查java instrumentation来执行此操作是的,有一些模拟库允许您这样做。一个是。从他们的观点来看,你需要这样的东西: @RunWith(PowerMockRunner.class) @Prepare

我正在测试一个函数,它接受几个参数,并根据它们的值调用不同的私有方法

我想检查函数是否总是调用正确的私有方法

因为我知道私有方法将要做什么,所以我可以检查最终结果,但是如果能够直接检查是否调用了正确的函数,会更方便,因为我已经测试了私有方法


有没有办法用存根替换privae方法?

您可以检查java instrumentation来执行此操作

是的,有一些模拟库允许您这样做。一个是。从他们的观点来看,你需要这样的东西:

@RunWith(PowerMockRunner.class)
@PrepareForTest(MyUnit.class)
public class TestMyUnit {

    @Test
    public void testSomething() {
        MyUnit unit = PowerMock.createPartialMock(MyUnit.class, "methodNameToStub");
        PowerMock.expectPrivate(unit, "methodNameToStub", param1).andReturn(retVal);

        EasyMock.replay(unit);

        unit.publicMethod(param1);

        EasyMock.verify(unit);

    }

}
然而,我本人确实不同意这种做法。您的单元测试应该测试输入、输出和副作用,仅此而已。通过确保正确调用私有方法,您所做的就是防止代码容易重构

换句话说,如果今后你想改变你单位的工作方式怎么办?这样做的安全方法是确保代码正在接受(通过)测试,然后重构代码(可能包括更改调用的内部方法),然后再次运行测试以确保没有破坏任何内容。使用您的方法,这是不可能的,因为您的测试测试的是确切的实现,而不是单元本身的行为。重构几乎总是会破坏测试,那么测试到底能给你带来多少好处呢


大多数情况下,您会希望这样做,因为您实际上正在考虑将这些私有方法作为自己的一个单元(这听起来很像您,因为您说您已经直接测试了这些私有方法!)。如果是这种情况,最好将该逻辑提取到它自己的类中,测试它,然后在剩下的代码中与新单元的模拟/存根版本交互。如果你这样做,你的代码有一个更好的结构,你不需要依靠巫毒魔法,那就是PowerMock。Michael Feathers是进行此类重构的绝佳参考。

作为解决方案之一,可以从内部类使用代理。您需要在必须测试的每个类中添加内部类。 但对于大型产品项目来说,这并不是一个很好的解决方案。它需要创建添加脚本,以便从发布文件(jar/war)中删除生成的类


但更简单的方法是使用PowerMock,如下面(或上面:)的注释中所述-

是否可以为所讨论的类提供另一个对象,将私有方法移动到该对象并将其公开?在这种情况下,很容易为该接口创建一个测试假人。

如果调用正确的“私有方法”没有可观察的外部结果,您确定要测试它吗?也许不应该


如果不管私有方法是否被调用,最终结果都是相同的,并且您仍然希望观察它的调用,那么您可以将该方法公开并将其移动到自己的类中,并模拟该类。然后,您可以验证(使用Mockito或类似的框架)是否正在调用您的方法。

代码覆盖工具通过在测试实际运行之前重新编写字节码来完成这类工作。所以,这是有可能的,但这不是小事


更新:编写一个需要调用“正确”私有方法的单元测试会让重构工作变得非常痛苦,因为这样你就必须重新编写所有的测试。这种做法违背了测试的目的。

在方法开始时在控制台上打印函数名。这样你就知道调用了什么函数。好的,这是调试而不是测试…@Vikiii:我认为这种做法违背了自动单元测试的理想。你为什么不检查结果?多个方法会返回相同的结果吗?你能建议我寻找什么吗?一些模拟框架也在使用此功能(我认为这是EasyMock),我在PowerMock中找不到相关内容。有很多方法可以测试私有方法,但没有方法可以满足我的需要。但也许我没认真看enough@delamere:链接确实表示它可以模拟私有方法。您可能希望将其与部分模拟结合使用。以下是链接:。在该示例中(测试一个具有调用私有方法的公共方法的类),它们会引导您部分模拟该类,然后设置对私有方法的期望。