Someone asked about the package organization of the project. In response, I moved the persistence-related classes into the persistence package. This required I believe one change to access level, and a number of import changes (which of course Eclipse will fix automatically).
I chose not to move the data access classes themselves--CustomerAccess, UserAccess, and associated test classes--to a different package yet. Keeping them with domain classes allows for some things to be stated at package level instead of public. Less work for now, in any case. I'm not worried about any level of effort in the future, since changes like these are easy and safe using Eclipse.
The new package organization:
The same someone was also concerned about the tests having to access the database so much. To start figuring out what's going to work best, I want to write some application-level code.
package application;
import junit.framework.*;
public class ApplicationTest extends TestCase {
public void testVerifyUser() {
final String name = "name";
final String password = "password";
Application application = new Application();
assertFalse(application.isRegistered(name, password));
application.registerUser(name, password);
assertTrue(application.isRegistered(name, password));
}
}
package application;
import domain.*;
public class Application {
public void registerUser(String name, String password) {
User user = new User(name, password);
new UserAccess().save(user);
}
public boolean isRegistered(String name, String password) {
User user = new UserAccess().find(name);
return user != null;
}
}
OK, there's a simple test, a failing one as expected. It'll be my beacon for guidance over the next several minutes.
The test immediately introduces a problem: I don't properly handle an empty result set in the JdbcAccess class. Driving a solution to this through tests, I first add a test for the Persister class that indicates what I want to happen when no rows are returned:
public void testFindNotFound() {
assertNull(persister.find(BAD_KEY));
}
Other interesting elements in PersisterTest:
private static final String BAD_KEY = "not found";
protected void setUp() {
access = new JdbcAccess() {
...
public List<String> executeQuery(String sql) {
lastSql = sql;
if (sql.indexOf(BAD_KEY) > -1)
return null;
return EXPECTED_ROW;
}
};
The change to Persister is minor:
public T find(String key) {
String sql = new SqlGenerator().createFindByKey(metadata.getTable(), metadata.getColumns(),
metadata.getKeyColumn(), key);
List<String> row = access.executeQuery(sql);
if (row == null)
return null;
return metadata.create(row);
}
The Persister change in turn triggers the need for changes in JdbcAccess via JdbcAccessTest:
public void testExecuteQueryNoResults() {
access.execute(createTableSQL());
assertNull(access.executeQuery("select x from " + TABLE + " where 1 = 0"));
}
JdbcAccess:
public List<String> executeQuery(String sql) {
try {
createStatement();
ResultSet results = statement.executeQuery(sql);
List<String> row = null;
if (results.next())
row = getRow(results);
results.close();
connection.close();
return row;
}
catch (SQLException e) {
throw new JdbcException(sql, e);
}
}
Now I'm back to the original Application test, which is now failing. Why? Well, because it's dealing with the database, and a previous run of the test added the user in question to the database tables.
There are a few options for a solution. The most obvious is to make sure that the database is cleaned out with each new unit test run. The better tactic is to start looking at inserting mocks. The dependence on the state of the database is one of many reasons we'll want mocks for our unit tests. Other reasons are availability of the database, contention during concurrent test runs, and speed of the entire test run.
I'll start dealing with these issues tomorrow.
Today's 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