【发布时间】:2020-08-06 05:03:29
【问题描述】:
我想编写多个依赖于调用数据库并从 ResultSet 构建对象的 JUnit 测试。
这个想法是不同的测试用例需要来自数据库的不同数量的元素。因此,next方法返回true的次数,以及对getString等类似方法的调用会有所不同。
这就是我尝试这样做的方式,但它抛出了如下所示的异常。
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Collection;
import java.util.LinkedList;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.OngoingStubbing;
@RunWith(MockitoJUnitRunner.class)
public class ForStackOverflow {
private static class Rule {
int id;
String name;
}
private static final String SQL = "select * from table";
@Mock
private Connection connection;
@Mock
private PreparedStatement statement;
@Mock
private ResultSet resultSet;
@Before
public void setup() throws Exception {
//
databaseManager.connection = connection;
when(connection.prepareStatement(SQL)).thenReturn(statement);
when(statement.executeQuery()).thenReturn(resultSet);
}
@Test
public void testSomething() throws Exception {
// setup
Rule rule;
Collection<Rule> rules = new LinkedList<>();
rule = new Rule();
rule.id = 0;
rule.name = "mock name 1";
rules.add(rule);
rule = new Rule();
rule.id = 1;
rule.name = "mock name 2";
rules.add(rule);
ResultSet resultSet = setupResultSet(rules);
databaseManager.queryDatabase();
verify(resultSet, times(rules.size() + 1)).next();
verify(resultSet, times(rules.size())).getInt(1);
verify(resultSet, times(rules.size())).getString(2);
}
private ResultSet setupResultSet(Collection<Rule> rules) throws Exception {
ResultSet resultSet = mock(ResultSet.class);
OngoingStubbing<Boolean> ongoingWhen = when(resultSet.next());
OngoingStubbing<Integer> ongoingGetInt = when(resultSet.getInt(1));
OngoingStubbing<String> ongoingGetString = when(resultSet.getString(2));
for (Rule rulePriority : rules) {
ongoingWhen.thenReturn(true);
ongoingGetInt.thenReturn(rulePriority.id);
ongoingGetString.thenReturn(rulePriority.name);
}
ongoingWhen.thenReturn(false);
return resultSet;
}
}
堆栈跟踪
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at ForStackOverflow.setupResultSet(ForStackOverflow.java:72)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3. you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed
at ForStackOverflow.setupResultSet(ForStackOverflow.java:73)
at ForStackOverflow.testSomething(ForStackOverflow.java:62)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
有没有办法动态地做这个存根?
谢谢!
【问题讨论】: