Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Thursday, February 11, 2016

Easy way to fill up ResultSet with data

Easy way to fill up ResultSet with data


I want to mock a ResultSet. Seriously. I'm refactoring one big complicated piece of code which is parsing data from ResultSet, and I want my code to behave identically. So, I need to write a unit test for the piece being refactored to be able to test this.

After googling I came up with 2 ideas:

  1. Use EasyMock, write looooong mocking sequence. VERY BAD solution: hard to add initial data, hard to change data, big test debugging promices.
  2. Use Apache Derby or HSQLDB to create in-memory DB, fill it from file or String array, query with some magical InMemoryDBUtils.query(sql). Then use that ResultSet. Unfortunately, I did not find any magical InMemoryDBUtils to write the test fast :-). IBM article "Isolated unit testing of persistence with Derby" seems just fine about what I need, though...

Second approach looks somewhat easier and much more supportable.

What would you advice for creating such a mock? (despite doctors, of course :-)? Am I missing an eyebrow some silver bullet? Possibly, DBUnit is the tool for this?

Thank you all for your time and answers.

WBR, DiaWorD

Answer by GWLlosa for Easy way to fill up ResultSet with data


If applicable, you could you take the result set you have now from your real data source, serialize it, and save the file. Then you could deserialize that result set for each of your unit tests, and you should be good to go.

Answer by erickson for Easy way to fill up ResultSet with data


As long as you're not calling most of the ResultSet methods, I would probably just load a delimited text file into a two-dimensional array, and implement the methods I actually needed, leaving the rest to throw an UnsupportedOperationException (which is the default implementation for stubbed-out methods in my IDE).

Answer by Yishai for Easy way to fill up ResultSet with data


DBUnit doesn't present a result set, to my knowledge, although it will well help you populate your in memory database.

I would say that a mocking framework is the wrong approach at this point. Mocking is about testing behavior and interaction, not just returning data, so it will likely get in your way.

I would instead either implement a result set interface, or create a dynamic proxy of a result set interface to a class that implements the methods you care about without having to implement the whole result set. You will likely find maintaining a class as easy as maintaining an in memory database (provided that the dataset under test is consistent), and probably easier to debug.

You could back up that class with DBUnit, where you take a snapshot of your result set with dbunit, and have dbunit read it back during the test from xml, and have your dummy result set read the data from dbunit's classes. This would be a reasonable approach if the data was mildly complex.

I would go for the in memory database if the classes were so coupled that they need to read data that was modified as part of the same test. Even then, I would consider using a copy of the real database until you managed to pull that dependency apart.

A simple proxy generation method:

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 generateProxy(Object realObject, Class... interfaces) {      return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject));  }  

Answer by matt for Easy way to fill up ResultSet with data


I've had success with the MockResultSet class from here: http://mockrunner.sourceforge.net/. It allows you to create a class that implements the ResultSet interface, and lets you set the values for each column and row.

If your methods are working with ResultSets of reasonable size, you should be able to create tests that return the values you need fairly easily.

Here's a simple example:

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());  

Answer by jason for Easy way to fill up ResultSet with data


I was looking for the same thing, a library to mock a ResultSet, and I eventually found it. Mockrunner can load a csv or xml file and create a MockResultSet automatically. It also mocks Connection and Statement, so all your JDBC stuff simply works, without even adding a JDBC driver to your classpath.

http://mockrunner.sourceforge.net

Answer by karthik m for Easy way to fill up ResultSet with data


I have written something for this same case. You can mock the resultset using Mockito. You can as well loop over the mock rows of resultset by mocking the resultset.next() with this piece of 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() {          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() {            @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() {            @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];      }  }  


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.