Java 绕过方法存根中的构造函数调用

Java 绕过方法存根中的构造函数调用,java,unit-testing,mockito,Java,Unit Testing,Mockito,我目前正在使用java JSP页面作为测试框架。我在这方面没有太多的经验。然而,有一个问题我找不到解决办法 问题是,我想测试一个不可变的类。您只能使用构造函数初始化属性。访问器(getter)可以检索这些值。但是,其中一个setter方法有一个执行另一个类的构造调用的方法 public class MyImmutableClass { private final String foo; private final String bar; private final int

我目前正在使用java JSP页面作为测试框架。我在这方面没有太多的经验。然而,有一个问题我找不到解决办法

问题是,我想测试一个不可变的类。您只能使用构造函数初始化属性。访问器(getter)可以检索这些值。但是,其中一个setter方法有一个执行另一个类的构造调用的方法

public class MyImmutableClass {
    private final String foo;
    private final String bar;
    private final int jeez;

    public MyImmutableClass(String f, String b, Integer j) {
        this.foo = setFoo(f);
        // same for other fields
    }

    private String setFoo(String newFoo) {
        String retVal = "";
        List<String> identifiers = new MyDataBaseHandler().getListOfIdentifiers(); // construct call
        if (identifiers.contains(newFoo)) {
            // ...
        }
        else {
            // ...
        }
        return retVal;
    }

    public boolean isValid() {
        // returns the correctness of this instance
    }
}
方法this.getIdentifiers()是一个私有方法,用于复制字符串列表。(为了测试起见,该列表中只放了3个元素)。这是为了确保标识符的验证正确地完成任务

然而,这个测试失败了。问题在于
getListOfIdentifiers()
在方法体中有一个私有方法调用。这会抛出一个NPE。显然,很难“绕过”在
getListOfIdentifiers()
方法中进行的构造调用。
callToMyPrivateMethod()
与数据库连接。由于单元测试在本地运行,因此无法建立数据库连接。因此,我想使用Mockito绕过返回值

public List<String> getListOfIdentifiers() {
    // ...
    callToMyPrivateMethod(); // throws NPE ...
    // ...
    return list;
}
这一行实际上是一条语句,它在数据库连接上创建一条准备好的语句(它本身不是null…keh)。准备好的声明抛出了一个NPE。将
mock(…)
替换为
spy(new MyDataBase())
ofc不起作用,因为它是与正在构造的实例不同的实例

我也尝试过
@InjectMock
这件事,但这无助于解决我的问题。可能是因为我没有正确地实现注入(doc对此不太清楚)


有没有办法解决这个问题,使Mockito框架拦截对
getListOfIdentifiers()
的调用,然后返回到我创建的列表?或者我是不是开始出现
XY
问题?

在测试方法中创建
新MyDataBaseHandler()
的实例

newmydatabasehandler()
是您的测试类与之通信的依赖项。你正确地认识到了这一点,因为你试图模仿它

但根据您当前的实现,您不能

有两种解决方案

  • 使用PowerMock(ito) 这将使您能够将调用重定向到
    newmydatabasehandler()
    ,以返回
    MyDataBaseHandler
    类的模拟。
    但我个人认为使用PowerMock是对糟糕设计的屈服

  • 改进你的设计。 IMHO在类中创建(直接)依赖项的实例违反了单一责任模式。依赖项的实例化不是类的责任

    您应该在
    MyImmutableClass
    之外创建
    MyDataBaseHandler
    的实例,并最好通过构造函数将其注入
    MyImmutableClass
    对象中

    然后,您就可以轻松地用已经创建的mock替换此依赖项


  • 有帮助吗?除非你能重构,否则看起来你必须使用PowerMock。啊,我对DI很熟悉。但是(我刚刚意识到)
    setFoo(…)
    并不是在我的示例中首先被调用的。向构造函数提供的其他参数将首先进行验证。如果验证程序成功,将调用
    setFoo(…)
    。我实际上是在限制数据库结构。但是,嘿,我刚刚意识到我可以提供一个功能足够多的flyweight db处理程序对象,并将其提供给对象构造函数。我回去工作后会调查的。
    public List<String> getListOfIdentifiers() {
        // ...
        callToMyPrivateMethod(); // throws NPE ...
        // ...
        return list;
    }
    
    java.lang.NullPointerException
        at package.MyDataBaseHandler.callToMyPrivateMethod(MyDataBaseHandler.java:67)
        at package.MyDataBaseHandler.getListOfIdentifiers(MyDataBaseHandler.java:25)