我目前正在使用Mockito作为我的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
}
}
为了测试这个不可变的类,我已经导入了Mockito并尝试了以下方法。
@RunWith(MockitoJUnitRunner.class)
public class MyImmutableClassTest {
@Test
public void validConstruction() throws Exception {
MyDataBaseHandler myDB = mock(MyDataBaseHandler.class);
doReturn(this.getIdentifiers()).when(myDB).getListOfIdentifiers();
MyImmutableClass m = new MyImmutableClass("foo", "bar", 1);
assertTrue(m.isValid());
}
}
方法this.getIdentifiers()
是一种重现字符串列表的私有方法。 (为了测试起见,只有3个元素放在该列表中)。这是为了确保标识符的验证能够正确地完成工作。
但是,此测试失败。问题是getListOfIdentifiers()
在方法体中有一个私有方法调用。这会引发NPE。显然,很难“绕过”getListOfIdentifiers()
方法中的构造调用。 callToMyPrivateMethod()
与数据库连接。由于单元测试是在本地运行的,因此无法建立数据库连接。因此,我想通过使用Mockito来绕过返回值。
public List<String> getListOfIdentifiers() {
// ...
callToMyPrivateMethod(); // throws NPE ...
// ...
return list;
}
NPE的报告:
java.lang.NullPointerException
at package.MyDataBaseHandler.callToMyPrivateMethod(MyDataBaseHandler.java:67)
at package.MyDataBaseHandler.getListOfIdentifiers(MyDataBaseHandler.java:25)
该行实际上是一个语句,它在数据库连接上创建一个准备好的语句(它本身不是null ... keh)。准备好的声明引发了NPE。将mock(...)
替换为spy(new MyDataBase())
ofc不起作用,因为它与正在构造的实例不同。
我也尝试了@InjectMock
这件事,但这无助于解决我的问题。可能是我没有正确实现注入事项(文档不是那么清楚)。
有没有办法解决这个问题,以便Mockito框架拦截对getListOfIdentifiers()
的调用,然后返回到我创建的列表?或者我是否正在盯着XY
问题?
答案 0 :(得分:0)
您在测试方法中创建new MyDataBaseHandler()
的实例。
new MyDataBaseHandler()
是您所测试的类与之通信的依赖项。你正确地认识到了,因为你试图模仿它。
但是根据您当前的实施情况,您无法做到。
有两种解决方案。
使用PowerMock(ito)
这样您就可以将调用重定向到new MyDataBaseHandler()
以返回MyDataBaseHandler
类的模拟
但我个人认为使用PowerMock是对糟糕设计的投降。
改善您的设计。 恕我直言在类中创建(直接)依赖项的实例违反了单一责任模式。依赖关系的实例化根本不是一个类的责任。
您应该在MyDataBaseHandler
之外创建MyImmutableClass
的实例,并将其注入MyImmutableClass
个对象,最好通过构造函数。
然后,您可以轻松地将此依赖项替换为您已创建的模拟。