MockRunnerのJDBC Mockを使ってみた

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レイヤで処理を行っているのでフレームワークを問わず使えるのもいい感じです。