web-dev-qa-db-fra.com

comment se moquer de resultset et le peupler en utilisant Mockito en Java

J'ai le code où je remplis Resultset avec CallableStatement.executeQuery(). J'ai moqué ResultSet et CallableStatement mais pour tester la méthode, je dois renseigner ResultSet

Voici le code de la méthode que je teste 

ResultSet rset = cs.executeQuery();
while (rset.next()) {
IndexVolatilityImpl tsImpl = new IndexVolatilityImpl();
tsImpl.setTradeDate(rset.getString("trade_date"));
tsImpl.setTradeTime(rset.getString("trade_time"));
tsImpl.setExprDate(rset.getString("expr_date"));
tsImpl.setSymbol(rset.getString("symbol"));
tsImpl.setTradePrice(rset.getDouble("trade_price"));
tsImpl.setContractMonth(rset.getString("contract_month"));
tsImpl.setMilliSecs(rset.getString("trade_time_thou"));
colIndexVolatilityImpl.add(tsImpl);

Je me suis moqué de CallableStatement et de ResultSet maintenant, car ils sont moqués, mon jeu est vide. Je voudrais peupler Resultset et le faire comme ci-dessous

resultSetMock = Mockito.mock(ResultSet.class);
Mockito.when(resultSetMock.getString("trade_date")).thenReturn("03/10/2011");
Mockito.when(resultSetMock.getString("trade_time")).thenReturn("12:24:56");
Mockito.when(resultSetMock.getString("expr_date")).thenReturn("03/19/2011");
Mockito.when(resultSetMock.getString("symbol")).thenReturn("VIX1");
Mockito.when(resultSetMock.getDouble("trade_price")).thenReturn(Double.valueOf("20.96"));
Mockito.when(resultSetMock.getString("contract_month")).thenReturn("1");
Mockito.when(resultSetMock.getString("trade_time_thou")).thenReturn("165");

Mockito.doReturn(resultSetMock).when(callableStatementMock).executeQuery();

Mais rset est null.

31
Tejas Shah

Vous devriez également simuler la méthode next() pour qu'elle renvoie true la première fois, car mockito renvoie false par défaut.

Mockito.when(resultSetMock.next()).thenReturn(true).thenReturn(false);
39
proactif

J'ai écrit quelque chose pour ce même cas. Vous pouvez vous moquer des résultats en utilisant Mockito. Vous pouvez également parcourir les maquettes de résultats en vous moquant de resultset.next () avec ce morceau de code.

// two dimensional array mocking the rows of database.
String[][] result = { { "column1", "column2" }, { "column1", "column2" } };

@InjectMocks
@Spy
private TestableClass testableClass;

@Mock
private Connection connection;

@Mock
private Statement statement;

@Mock
private ResultSet resultSet;

@BeforeTest
public void beforeTest() {
    MockitoAnnotations.initMocks(this);
}

@BeforeMethod
public void beforeMethod() throws SQLException {
    doAnswer(new Answer<Connection>() {
        public Connection answer(InvocationOnMock invocation)
                throws Throwable {
            return connection;

        }
    }).when(testableClass).getConnection();

    when(connection.createStatement()).thenReturn(statement);
    when(statement.executeQuery(anyString())).thenReturn(resultSet);
    final AtomicInteger idx = new AtomicInteger(0);
    final MockRow row = new MockRow();

    doAnswer(new Answer<Boolean>() {

        @Override
        public Boolean answer(InvocationOnMock invocation) throws Throwable {
            int index = idx.getAndIncrement();
            if (result.length <= index) {
                return false;
            } 
            String[] current = result[index];
            row.setCurrentRowData(current);
            return true;

        }

        ;
    }).when(resultSet).next();

    doAnswer(new Answer<String>() {

        @Override
        public String answer(InvocationOnMock invocation) throws Throwable {
            Object[] args = invocation.getArguments();
            int idx = ((Integer) args[0]).intValue();
            return row.getColumn(idx);
        }

        ;
    }).when(resultSet).getString(anyInt());
}

static class MockRow {
    String[] rowData;

    public void setCurrentRowData(String[] rowData) {
        this.rowData = rowData;
    }

    public String getColumn(int idx) {
        return rowData[idx - 1];
    }
}
7
karthik m

J'ai récrit un peu la réponse de @karthik m pour rendre le moqueur de ResultSet autonome:

En utilisant la classe ci-dessous, je peux facilement exporter le résultat d'une requête au format csv et écrire un test autour de cela.

Toutes les méthodes de ResultSet ne sont pas moquées, car je n'en avais pas besoin, mais leur utilisation devrait être relativement simple.

import no.di.common.util.StringUtil;
import org.Apache.commons.io.FileUtils;
import org.Apache.commons.io.LineIterator;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import Java.io.File;
import Java.io.IOException;
import Java.sql.ResultSet;
import Java.sql.SQLException;
import Java.util.ArrayList;
import Java.util.HashMap;
import Java.util.List;
import Java.util.Map;
import Java.util.concurrent.atomic.AtomicInteger;

import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;

/**
 * Creates a Mock of a ResultSet
 */
public class ResultSetMocker {

    private Map<String, Integer> columnNames = new HashMap<>();

    private Object[][] result;

    public ResultSetMocker(String filename) throws IOException {
        loadData(filename);
    }

    private void loadData(String filename) throws IOException {
        List<Object[]> toRet = new ArrayList<>();

        int numberOfParts = 0;
        LineIterator it = FileUtils.lineIterator(new File(filename), "ISO8859-1");
        try {
            String names = it.nextLine();
            String[] name = names.split(";");
            for(int i = 0; i < name.length; i++) {
                columnNames.put(name[i], i + 1);
            }

            while (it.hasNext()) {
                String line = it.nextLine();

                String[] parts = line.split(";");
                numberOfParts = parts.length;
                Object[] result = new Object[parts.length];
                for(int i = 0; i < parts.length; i++) {
                    if(parts[i].equals("(null)"))
                        result[i] = null;
                    else if(StringUtil.isAllNumeric(parts[i]))
                        result[i] = Integer.parseInt(parts[i]);
                    else
                        result[i] = parts[i];
                }

                toRet.add(result);
            }
        } finally {
            it.close();
        }

        result = toRet.toArray(new Object[toRet.size()][numberOfParts]);
    }

    public ResultSet getResultSet() throws SQLException, IOException {
        ResultSet resultSet = mock(ResultSet.class);

        final AtomicInteger idx = new AtomicInteger(0);
        final MockRow row = new MockRow(columnNames);

        doAnswer(new Answer<Boolean>() {
            @Override
            public Boolean answer(InvocationOnMock invocation) throws Throwable {
                int index = idx.getAndIncrement();
                if (result.length > index) {
                    row.setCurrentRowData(result[index]);
                    return true;
                } else
                    return false;
            }
        }).when(resultSet).next();

        doAnswer(new Answer<String>() {
            @Override
            public String answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                int idx = (Integer) args[0];
                return row.getString(idx);
            }
        }).when(resultSet).getString(anyInt());

        doAnswer(new Answer<String>() {
            @Override
            public String answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                String name = (String) args[0];
                return row.getString(name);
            }
        }).when(resultSet).getString(anyString());

        doAnswer(new Answer<Object>() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                String name = (String) args[0];
                return row.getObject(name);
            }
        }).when(resultSet).getObject(anyString());

        doAnswer(new Answer<Integer>() {
            @Override
            public Integer answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                String name = (String) args[0];
                return row.getInt(name);
            }
        }).when(resultSet).getInt(anyString());

        return resultSet;
    }

    static class MockRow {
        Object[] rowData;
        private Map<String, Integer> columnNames;

        public MockRow(Map<String, Integer> columnNames) {

            this.columnNames = columnNames;
        }

        public void setCurrentRowData(Object[] rowData) {
            this.rowData = rowData;
        }

        public String getString(int idx) {
            return (String)rowData[idx - 1];
        }

        public String getString(String name) {
            return (String)rowData[columnNames.get(name) - 1];
        }

        public Object getObject(String name) {
            return rowData[columnNames.get(name) - 1];
        }

        public Integer getInt(String name) {
            return (Integer)rowData[columnNames.get(name) - 1];
        }
    }
}
4
Alexander Kjäll

Un peu tard pour le jeu ici, mais il semble que tout ce dont vous aviez besoin sur votre Mock original était-ce ...

Mockito.when(resultSetMock.next()).thenReturn(true);

Cela est nécessaire pour que le mappeur (quel que soit le moyen utilisé pour mapper le jeu de résultats) sache qu'il existe des données dans le jeu de résultats.

0
Dave