I want to write multiple JUnit tests that depend on calling a database and building objects out of a ResultSet.
The idea is that different test cases need different number of elements coming from the database. Therefore, the number of times the next method returns true, and the call to getString
and similar methods will vary.
This is how I tried to do it, but it's throwing the exception shown below.
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;
}
}
The Stack trace
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)
Is there a way to do this stubbing dynamically?
Thank you!