When extracting methods into another class, the tests that cover these methods may be best suited for staying on the original class. This leaves you with no tests directly covering the extracted code.
In the case of the JdbcAccess code, the execute and executeQuery methods remain covered indirectly through tests in UserTest. My preference is to take the time and immediately add tests that directly exercise the newly exposed public interface. Here's JdbcAccessTest:
import java.sql.*;
import java.util.*;
import junit.framework.*;
public class JdbcAccessTest extends TestCase {
private static final String TABLE = "JdbcAccessTest";
private JdbcAccess access;
protected void setUp() {
access = new JdbcAccess();
}
protected void tearDown() throws SQLException {
access.execute("drop table " + TABLE);
}
public void testExecute() throws SQLException {
access.execute(createTableSQL());
assertEquals(0, count());
}
public void testExecuteQuery() throws SQLException {
access.execute(createTableSQL());
List<String> row = access.executeQuery(createCountSQL());
assertEquals(1, row.size());
assertEquals(0, getInt(row, 0));
}
private int count() throws SQLException {
List<String> row = access.executeQuery(createCountSQL());
return getInt(row, 0);
}
private String createCountSQL() {
return "select count(*) from " + TABLE;
}
private int getInt(List<String> row, int column) {
return Integer.parseInt(row.get(column));
}
private String createTableSQL() {
return "create table " + TABLE + " (x varchar(1))";
}
}
In order to get this working, I had to make a small change to the JdbcAccess code:
private List<String> getRow(ResultSet results) throws SQLException {
List<String> row = new ArrayList();
for (int i = 1; i <= results.getMetaData().getColumnCount(); i++)
row.add(results.getString(i));
return row;
}
So getRow is now generalized to any number of columns, which it still presumes are all Strings. This adds some expense in parsing the column when it's not a String, as in the JdbcAccessTest method getInt (used for column count). It's an expense that I'm willing to accept for the time being, but it does suggest that I want to make a note about running performance tests at some time in the future.
The other relevant lesson today is that I followed the refactoring step of eliminating duplication in the test, up to a point. That point is to the readability of the test in question, or more specifically, to the point that the test still clearly shows the thing that's being tested. Eliminating duplication one more step would mean removing the execute call from testExecute, and the executeQuery call from testExecuteQuery. I'd rather not obscure that code. This is an example of where simple design rule #3 (expressiveness of code) can trump #2, elimination of duplication. Usually for me, this occurs only in test code.
February 2004 March 2004 May 2004 September 2004 October 2004 January 2005 February 2005 September 2005 October 2005 November 2005 December 2005 January 2006 February 2006 March 2006 June 2006 August 2006 January 2007 February 2007 March 2007 April 2007 September 2007 October 2007 November 2007 December 2007 January 2008