S2UnitはDBを使ったユニットテストの支援機能としてExcelファイルからDBにテスト用データを投入したり、ExcelファイルとDBの内容を比較したりすることができます。ただ、実際にやってみるとわかるのですがこのExcelファイルのメンテナンスコストが馬鹿になりません。
そこで、実際にDBにアクセスするのではなく、フレームワークやJDBCドライバのレイヤで発行されたSQLを横取りし、期待通りのSQLが発行されたのかどうかを確認するという方法はどうだろう?と考えました。そういうライブラリを自作しようかとも思ったのですが(実際途中まで作っていたのですが)、世の中同じことを考える人はいるもので、MockRunnerのJDBC Mockという機能を使うとそのものズバリなことができるようです。
というわけでS2JDBCを使ったサービスクラスのテストをS2UnitとJDBC Mockを使って書いてみました。上記のサンプルではテストケースがBasicJDBCTestCaseAdapterというクラスを継承していますが、基本的にはJDBCTestModuleやJDBCMockObjectFactoryの生成と破棄を行っているだけなので、その部分だけsetUp()メソッドとtearDown()メソッドに移植してあります。
public class UserServiceTest extends S2TestCase { private UserService userService; private JDBCTestModule jdbcTestModule; private JDBCMockObjectFactory jdbcMockObjectFactory; protected void setUp() throws Exception { super.setUp(); jdbcMockObjectFactory = new JDBCMockObjectFactory(); jdbcTestModule = new JDBCTestModule(jdbcMockObjectFactory); include("app.dicon"); } protected void tearDown() throws Exception { super.tearDown(); jdbcMockObjectFactory.restoreDrivers(); jdbcTestModule = null; jdbcMockObjectFactory = null; } public void testGetUserInfoTx() { MockConnection connection = jdbcMockObjectFactory.getMockConnection(); PreparedStatementResultSetHandler statementHandler = connection.getPreparedStatementResultSetHandler(); MockResultSet result = statementHandler.createResultSet(); result.addRow(new Object[]{"takezoe", "password"}); statementHandler.prepareGlobalResultSet(result); UserInfo userInfo = userService.getUserInfo("takezoe", "password"); String expectSql = "select " + "T1_.USER_ID as C1_," + " T1_.PASSWORD as C2_ " + "from USER_INFO T1_ " + "where ((T1_.USER_ID = ?) and (T1_.PASSWORD = ?))"; jdbcTestModule.verifySQLStatementExecuted(expectSql); jdbcTestModule.verifySQLStatementParameter(expectSql, 0, 1, "takezoe"); jdbcTestModule.verifySQLStatementParameter(expectSql, 0, 2, "password"); assertNotNull(userInfo); assertEquals("takezoe", userInfo.userId); assertEquals("password", userInfo.password); } }
とりあえずこれでやりたかったことは実現できそう。JDBCレイヤで処理を行っているのでフレームワークを問わず使えるのもいい感じです。