SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

オイシックスの事例から学ぶ、JavaのWebアプリに自動テストを導入する方法

DBUnitを使って、ユニットテストのテストデータを作成する

オイシックスの事例から学ぶ、JavaのWebアプリに自動テストを導入する方法 第4回

JNDIユーティリティの利用

 次に弊社のWebアプリケーションではJNDIを使用してDB接続をしていて、コンテナが提供しているJNDIユーティリティーを使っています。そのため、テストクラスではコンテナを利用せずにどのようにその部分を吸収したかを説明させていただければと思います。

 まず、JNDIとはネーミングサービスやディレクトリーサービスを利用するための、インターフェースになります。今回の使用例でざっくり言うとnameとJDBCの接続情報をbind(関連づけ)しておき、使いたい時にはnameからJDBCの接続情報を検索して利用する仕組みです。詳細はdeveloperWorksで詳しく解説されているので、ご参照ください。

 サーブレットコンテナが動作していない環境では、「JUnit JNDI DataSource helper package」というライブラリ使う方法もありますが、弊社では使用しておりません。そのため、この部分では使用せずにJNDIでのDB接続をテストコードに組み込む方法を説明します。実際には以下のような登場人物で実現しています。

 TestEnvironmentクラスはテストケース実行前にテスト環境用の設定をするクラスです。TestDBクラスは、JNDIを使ったDB接続情報を設定しているクラスで、TestEnvironmentクラスのprepare()メソッドからTestDBクラスのprepareメソッドを呼び、JNDIの設定をします。そして、HogeHogeTestクラスがテストクラスで、@BeforeClassアノテーションが付いたprepare()メソッドの中でTestEnvironmentクラスのprepare()メソッドを呼ぶ形にしています。

 それでは、まずHogeHogeTestクラスのソースを元に説明したいと思います。

HogeHogeTest.java
01: public class HogeHogeTest {
02: 
03:     private static TestData testData;
04: 
05:     @BeforeClass
06:     public static void prepare() throws Exception {
07:         TestEnvironment.prepare();
08:         testData = new TestData("src/com/oisix/sample/HogeHogeTest.xls");
09:         testData.load();
10:     }
11: 
12:     @Test
13:     public void testHogeHoge () {
14:     :
15:     :
16:     :
17:     }
18:     :
19:     :
20:     :
21:     @AfterClass
22:     public static void cleanUp() {
23:         testData.cleanup();
24:         testData = null;
25:     }
26: }

 このコードの@BeforeClassでテストデータのインポート、@AfterClassでインポートしたテストデータのクリア処理をしています。もちろんDBUnitで行っています。DBUnitを使用すれば、このようにシンプルで分かりやすくテストデータの作成処理をテストクラスに組み込むことができるようになります。実際には3行目で定義しているTestDataクラスのload()メソッドでデータのインポート処理を、cleanup()メソッドでインポートしたデータのクリア処理をDBUnitを使用して記述しています。

テスト環境の設定

 続いてTestEnvironmentのソースの説明したいと思います。以下がソースになるのでさっとお読みいただければと思います。

TestEnvironment.java ※弊社自作クラス
01: package com.oisix.common;
02: 
03: import java.io.File;
04: import java.util.Date;
05: 
06: import org.apache.commons.lang.StringUtils;
07: 
08: import com.oisix.oisystemfr.util.DateUtil;
09: 
10: public class TestEnvironment {
11: 
12:     public static void prepare() {
13:         TestDB.prepare();
14:         TestEnvironment.prepareSystemProperties();
15:         return;
16:     }
17: 
18:     public static void prepareSystemProperties() {
19:         setFixedProperty();
20:         setDefaultTestDate();
21:     }
22:     
23:     :
24:     :省略
25:     :
26: 
27: } 

 さきほども説明しましたが、このクラスはテスト環境用の設定をするクラスになります。

12: public static void prepare() {
13:     TestDB.prepare();
14:     TestEnvironment.prepareSystemProperties();
15:     return;
16: }

 12~16行目のprepare()メソッドは、テストクラスの@BeforeClass付けたメソッドで呼び出し、テストケース実行前に実行します。13行目のTestDB.prepare();でJNDIの設定をします。14行目はシステムプロパティ全般を設定しているコードで、今回の説明には不要なので割愛します。

 続いて、JNDIの設定をしているTesDBクラスについて見ていきたいと思います。

TestDB.java ※弊社自作クラス
01: package com.oisix.common;
02: 
03: import java.io.File;
04: import java.io.FileReader;
05: import java.util.Properties;
06: 
07: import javax.naming.Context;
08: import javax.naming.InitialContext;
09: 
10: import oracle.jdbc.pool.OracleConnectionPoolDataSource;
11: 
12: import org.hibernate.SQLQuery;
13: 
14: import com.oisix.oisystemfr.persistence.EntityManager;
15: import com.oisix.oisystemfr.persistence.EntityManagerFactory;
16: import com.oisix.oisystemfr.persistence.EntityTransaction;
17: 
18: public class TestDB {
19: 
20:     private static boolean isDone = false;
21:     public static String USER_ID;
22: 
23:     public static void prepare() {
24:         if (EntityManagerFactory.exists()) {
25:             EntityManagerFactory.release();
26:         }
27: 
28:         if (isDone) {
29:             return;
30:         }
31:         try {
32:             Properties props = new Properties();
33:             props.load(new FileReader(new File("junit/db.properties")));
34: 
35:             System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
36:                     "org.apache.naming.java.javaURLContextFactory");
37:             System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");
38:             InitialContext ic = new InitialContext();
39:             ic.createSubcontext("java:");
40: 
41:             OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
42:             ds.setURL(props.getProperty("core.url"));
43:             ds.setUser(props.getProperty("core.user"));
44:             ds.setPassword(props.getProperty("core.password"));
45:             ic.bind(props.getProperty("core.jndi"), ds);
46:             USER_ID = ds.getUser();
47: 
48:             OracleConnectionPoolDataSource refer = new OracleConnectionPoolDataSource();
49:             refer.setURL(props.getProperty("refer.url"));
50:             refer.setUser(props.getProperty("refer.user"));
51:             refer.setPassword(props.getProperty("refer.password"));
52:             ic.bind(props.getProperty("refer.jndi"), refer);
53:             isDone = true;
54:         } catch (Exception e) {
55:             throw new RuntimeException(e);
56:         }
57:     }
58:     :
59:     :省略
60:     :
61: }

 23行目のprepare()メソッドを見ていただければと思います。このメソッドの中でJNDIの設定を行っています。それではコードを説明していきたいと思います。

24: if (EntityManagerFactory.exists()) {
25:     EntityManagerFactory.release();
26: }

 まず24~26行目。この処理はキャッシュされているHibernateのsessionの有無をチェックして、クローズしている部分です。テストコードごとに実行して、sessionがまっさらな状態でテストケースが実行されるようにしています。

28: if (isDone) {
29:     return;
30: }

 続いて、28~30行目はすでにJNDIの設定をしているかを判定している部分で、すでに設定済みの場合はJNDIの設定を行わないようにisDoneというフラグを利用して制御しています。

32: Properties props = new Properties();
33: props.load(new FileReader(new File("junit/db.properties")));

 32~33行目はdb.propertiesというDB接続情報を持っているファイルを読み込んでいて、以降のコードで、その情報を使用します。

35: System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
36:         "org.apache.naming.java.javaURLContextFactory");
37: System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");
39: InitialContext ic = new InitialContext();
40: ic.createSubcontext("java:");

 35~40行目はJNDIを使用する準備をしているコードです。

 これらの行については、JNDIを利用してネーミングサービスへbindする時のお作法であるため、詳しい解説は割愛させていただければと思います。ポイントだけ言うと、36行目のファクトリーの指定で弊社ではTomcatをベースにしたJ2EEサーバを利用しているので、" org.apache.naming.java.javaURLContextFactory"を指定しています。

 詳しいことについては上記で紹介したサイトをご参照ください。

41: OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
42: ds.setURL(props.getProperty("core.url"));
43: ds.setUser(props.getProperty("core.user"));
44: ds.setPassword(props.getProperty("core.password"));
45: ic.bind(props.getProperty("core.jndi"), ds);
46: USER_ID = ds.getUser();

 41~46行目については、41~44行目でJDBCの接続情報をOracleConnectionPoolDataSourceのオブジェクトにセットして、45行目でプロパティに記述されている名前を使用してbind(関連付け)をしています。46行目については、説明不要の行なので無視してください。

48: OracleConnectionPoolDataSource refer = new OracleConnectionPoolDataSource();
49: refer.setURL(props.getProperty("refer.url"));
50: refer.setUser(props.getProperty("refer.user"));
51: refer.setPassword(props.getProperty("refer.password"));
52: ic.bind(props.getProperty("refer.jndi"), refer);
53: isDone = true;

 続いて、48行目から53行目は41~46行目と同様でJDBCの接続情報(参照系DB、注2)のbind(関連付け)をしているコードになります。53行目はネーミングサービスへのJDBC情報の関連付けが完了したので、isDoneというフィールド変数にtrueをセットしています。

 弊社では参照にしか使わないテーブルを参照用のDBにも作っている。

 41~53行目についてもJNDIを利用してネーミングサービスへbindする時のお作法になります。ポイントとしては、データソースに" OracleConnectionPoolDataSource"を使用している部分になります。使用しているJDBCによって異なるので注意してください。TestDB.java の説明は以上になります。

次のページ
オイシックスでのDBUnitの導入事例

この記事は参考になりましたか?

オイシックスの事例から学ぶ、JavaのWebアプリに自動テストを導入する方法連載記事一覧

もっと読む

この記事の著者

山田 昌平(オイシックス株式会社)(ヤマダ ショウヘイ)

オイシックスでは 運用→開発→開発推進を担当してきました。あと、ITイベントの協賛も担当しております。イベントは、技術的な面、エンジニアとしての考え方など、本当に学ぶことが多いのでおすすめです。お会いすることもあると思いますので気軽に声をお掛けください。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/8214 2014/10/30 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー