Oracle + JUnit4 で DBTestCaseを継承せずに dbUnit を使う
Oracle + JUnit4 で DBTestCaseを継承せずに dbUnit 使おうと思ったら、ちょっと苦労したのでメモ。
http://www.dbunit.org/howto.html#noextend によると、DBTestCase を継承しないで DBUnit のテストケースを書くには、dbUnit 2.2以降はIDatabaseTester が使えるようである。そこで、サンプルをもとに、以下の様に書いてみた。
public class HogeTest { private static IDatabaseTester dbTester; @BeforeClass public static void setUpBeforeClass() throws Exception { dbTester = new JdbcDatabaseTester("oracle.jdbc.driver.OracleDriver" ,"jdbc:oracle:thin:@xxxx:1521:xxx" ,"user" ,"pass"); dbTester.setSetUpOperation(DatabaseOperation.INSERT); dbTester.setTearDownOperation(DatabaseOperation.DELETE); IDataSet dataset = new FlatXmlDataSetBuilder().build(new FileInputStream("testdata/hogeDataset.xml" )); dbTester.setDataSet(dataset); } @AfterClass public static void tearDownAfterClass() throws Exception { } @Before public void setUp() throws Exception { dbTester.onSetup(); } @After public void tearDown() throws Exception { dbTester.onTearDown(); } @Test public void testMethod() { // test } }
これでテストを実行すると、以下の様なエラーが発生する。
AmbiguousTableNameException
これは、http://www.dbunit.org/faq.html#AmbiguousTableNameException に記載があった。
スキーマ名を指定せよとのこと。とくに、Oracle の場合は、スキーマ名を大文字でしてする必要があるらしい。
以下の様に書き換える。
dbTester = new JdbcDatabaseTester("oracle.jdbc.driver.OracleDriver" ,"jdbc:oracle:thin:@xxxx:1521:xxx" ,"user" ,"pass","SCHEMA");
これで、AmbiguousTableNameException は発生しなくなった。
しかし、今度は、dbTester.onSetup() 、テストデータの登録時に以下の様な例外が発生するようになった。
org.dbunit.dataset.NoSuchColumnException:
dataset の xml に誤りは無く、Column名が間違っていたわけではない。
ぐぐってみると、dataTypeFactory とやらを Oracle 用にしてみれば良いらしい。そこで、以下の記述を追加する。
dbTester.getConnection().getConfig().setProperty(DatabaseConfig. PROPERTY_DATATYPE_FACTORY, new OracleDataTypeFactory());
しかし、これでは例外が解決しなかった。
考えたあぐねて、デバッグモードでdbTester.getConnection().getConfig() のプロパティを見てみたら、DefaultDataTypeFactory のままだった。
なぜ設定が反映されないのか。さっぱりわからなくなって、 JdbcDatabaseTester#getConnection のソース読んだら以下の様になっていた。
public IDatabaseConnection getConnection() throws Exception { logger.debug("getConnection() - start"); assertNotNullNorEmpty( "connectionUrl", connectionUrl ); Connection conn = null; if( username == null && password == null ){ conn = DriverManager.getConnection( connectionUrl ); }else{ conn = DriverManager.getConnection( connectionUrl, username, password ); } return new DatabaseConnection( conn, getSchema() ); }
最後でDatabaseConnectionをnewしてやがる…
つまり、getConnectionでは常に新しいIDatabaseConnectionが返るので、せっかくプロパティをセットしても保持してくれないのだ。
ちなみに、他のIDatabaseTesterの実装も同様の実装だった。
しょうが無いので、JdbcDatabaseTesterを継承し、getConnectionをオーバーライドしてその都度プロパティをセットするようにした。
最終的には、以下の様なコードになった。
public class HogeTest { private static IDatabaseTester dbTester; @BeforeClass public static void setUpBeforeClass() throws Exception { dbTester = new JdbcDatabaseTester("oracle.jdbc.driver.OracleDriver" ,"jdbc:oracle:thin:@xxxx:1521:xxx" ,"user" ,"pass","SCHEMA") { @Override public IDatabaseConnection getConnection() throws Exception { IDatabaseConnection conn = super.getConnection(); conn.getConfig().setProperty(DatabaseConfig. PROPERTY_DATATYPE_FACTORY, new OracleDataTypeFactory()); return conn; } }; dbTester.setSetUpOperation(DatabaseOperation.INSERT); dbTester.setTearDownOperation(DatabaseOperation.DELETE); IDataSet dataset = new FlatXmlDataSetBuilder().build(new FileInputStream("testdata/hogeDataset.xml" )); dbTester.setDataSet(dataset); } @AfterClass public static void tearDownAfterClass() throws Exception { } @Before public void setUp() throws Exception { dbTester.onSetup(); } @After public void tearDown() throws Exception { dbTester.onTearDown(); } @Test public void testMethod() { // test } }
これでようやく動作した。