una recorrer mostrar llenar ejemplo datos consultas conectar con java unit-testing jdbc mocking resultset

recorrer - mostrar datos de una base de datos en java



Forma fácil de completar ResultSet con datos (6)

DBUnit no presenta un conjunto de resultados, que yo sepa, aunque le ayudará a llenar su base de datos de memoria.

Diría que un marco burlón es el enfoque equivocado en este punto. Burlarse se trata de probar el comportamiento y la interacción, no solo devolver datos, por lo que es probable que se interponga en su camino.

En su lugar, implementaría una interfaz de conjunto de resultados o crearía un proxy dinámico de una interfaz de conjunto de resultados para una clase que implemente los métodos que le interesan sin tener que implementar todo el conjunto de resultados. Es probable que encontrar el mantenimiento de una clase sea tan fácil como mantener una base de datos en memoria (siempre que el conjunto de datos bajo prueba sea consistente), y probablemente más fácil de depurar.

Puede hacer una copia de seguridad de esa clase con DBUnit, donde toma una instantánea de su conjunto de resultados con dbunit, y lee dbunit durante la prueba desde xml, y hace que su conjunto de resultados ficticio lea los datos de las clases de dbunit. Este sería un enfoque razonable si los datos fueran levemente complejos.

Me gustaría ir a la base de datos en memoria si las clases estaban tan acopladas que necesitan leer datos que se modificaron como parte de la misma prueba. Incluso entonces, consideraría usar una copia de la base de datos real hasta que haya logrado separar esa dependencia.

Un método simple de generación de proxy:

private static class SimpleInvocationHandler implements InvocationHandler { private Object invokee; public SimpleInvocationHandler(Object invokee) { this.invokee = invokee; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { method = invokee.getClass().getMethod(method.getName(), method.getParameterTypes()); if (!method.isAccessible()) { method.setAccessible(true); } try { return method.invoke(invokee, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } } public static <T> T generateProxy(Object realObject, Class... interfaces) { return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject)); }

Quiero burlarme de un ResultSet. Seriamente. Estoy refaccionando una gran pieza complicada de código que está analizando datos de ResultSet, y quiero que mi código se comporte de manera idéntica. Entonces, necesito escribir una prueba unitaria para la pieza que se está refactorizando para poder probar esto.

Después de buscar en Google, surgieron 2 ideas:

  1. Use EasyMock, escriba looooong secuencia de burla. Solución MUY MALA: datos iniciales difíciles de agregar, datos difíciles de cambiar, grandes promesas de depuración de pruebas.
  2. Utilice Apache Derby o HSQLDB para crear una base de datos en memoria, llenarla desde un archivo o matriz de cadenas, consultar con InMemoryDBUtils.query (sql) mágico. Luego usa ese ResultSet. Desafortunadamente, no encontré ningún InMemoryDBUtils mágico para escribir la prueba rápidamente :-). El artículo de IBM "Prueba unitaria aislada de persistencia con Derby" parece estar bien sobre lo que necesito, aunque ...

El segundo enfoque parece algo más fácil y mucho más compatible.

¿Qué aconsejarías para crear semejante simulacro? (a pesar de los médicos, por supuesto :-)? ¿Me estoy perdiendo una ceja con una bala de plata? Posiblemente, ¿DBUnit es la herramienta para esto?


He escrito algo para este mismo caso. Puede simular el conjunto de resultados usando Mockito. También puede recorrer las filas simuladas del conjunto de resultados burlándose del conjunto de resultados.next () con este fragmento de código.

// 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) { String[] current = result[index]; row.setCurrentRowData(current); 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]).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]; } }


He tenido éxito con la clase MockResultSet desde aquí: http://mockrunner.sourceforge.net/ . Le permite crear una clase que implementa la interfaz ResultSet y le permite establecer los valores para cada columna y fila.

Si sus métodos funcionan con ResultSets de tamaño razonable, debería poder crear pruebas que devuelvan los valores que necesita con bastante facilidad.

Aquí hay un ejemplo simple:

MockResultSet rs = new MockResultSet("myMock"); rs.addColumn("columnA", new Integer[]{1}); rs.addColumn("columnB", new String[]{"Column B Value"}); rs.addColumn("columnC", new Double[]{2}); // make sure to move the cursor to the first row try { rs.next(); } catch (SQLException sqle) { fail("unable to move resultSet"); } // process the result set MyObject obj = processor.processResultSet(rs); // run your tests using the ResultSet like you normally would assertEquals(1, obj.getColumnAValue()); assertEquals("Column B Value", obj.getColumnBValue()); assertEquals(2.0d, obj.getColumnCValue());


Mientras no llame a la mayoría de los métodos ResultSet , probablemente solo cargue un archivo de texto delimitado en una matriz bidimensional e implemente los métodos que realmente necesitaba, dejando el resto para lanzar una UnsupportedOperationException (que es la predeterminada implementación para métodos apagados en mi IDE).


Si corresponde, podría tomar el conjunto de resultados que tiene ahora de su fuente de datos real, serializarlo y guardar el archivo. Entonces podrías deserializar ese conjunto de resultados para cada una de tus pruebas unitarias, y deberías estar listo para continuar.


Mockrunner puede cargar un archivo CSV o XML y crear un MockResultSet automáticamente. También puede simular Connection y Statement, por lo que todo su material JDBC simplemente funciona, sin siquiera agregar un controlador JDBC a su classpath.