JUnit + DBUnitでExcelデータを使ったテストデータ管理術
はじめに
JUnitを使ったテストを書くとき、データベースのテーブルに必要なデータを毎回用意するのって意外と手間ですよね。
そんなときに便利なのが@Beforeアノテーション。これを使えば、テストが始まる前に自動でテーブルにデータを登録してくれるので、毎回同じ準備を繰り返す必要がなくなります。
ただ、JUnitのテストを書くとき、テストケースごとにまったく違うデータや環境でテストしたいことって結構ありますよね。
そんなときにありがちな落とし穴が「@Beforeでまとめてセットアップすると全部同じになっちゃう」という問題です。
💡補足:JUnit5では@BeforeEachとして提供されています(JUnit4では@Before)。
意味は同じで「各テストの実行前に実行されるメソッド」を定義します。
JUnitの@Before(または@BeforeEach)は便利ですが、テストごとに異なるデータを使いたいときは、テストメソッド内で準備を書く方が安全です。こうするとテストの独立性が上がり、あとで問題が起きたときにも原因を特定しやすくなります。
@Beforeを使うと便利なケース
- どのテストでも同じデータを使う場合
 - 共通的なモック設定やDIの初期化など、すべてのテストに共通する準備がある場合
 - テスト対象がデータに依存しないロジック中心のとき
 
@Beforeを使わない方がいいケース
- テストごとに異なるDB状態や入力データを再現したい場合
 - 各テストで結果を比較したり差異を検証したい場合
 - データの初期化やクレンジングをExcelなど外部ファイルで管理したい場合
 
こういったケースでは、テストメソッドごとに明示的にセットアップを記述することで、より正確で独立したテストが実現できます。
ExcelデータでDBを初期化する方法
ここでは、DBUnitを使ってExcelファイル(.xlsx)からDBを初期化する方法を紹介します。
これにより、テストデータをファイルで簡単に切り替えられるようになります。
DBUnitを使うメリット
- Excelでテストデータを可視的に管理できる
 - CLEAN_INSERTによりテーブル初期化を自動化できる
 - 異なるテストケースごとにデータセットを切り替えるだけで再利用可能
 - SQLを直接書かずに済むため、テストの可読性が高い
 
フォルダ構成(一部抜粋)
batch/
├── src/
│   ├── main/
│   │   ├── java
│   │      ├── AAAAA.java
│   ├── test/
│   │   ├── java
│   │   │  ├── AAAAATest.java
│   │   ├── resources
│   │      ├── TestData_case1.xlsx
│   │      ├── TestData_case2.xlsx
テストコード例(AAAAATest.java)
以下のコードは、Spring Batchのジョブをテストする例です。
ここではJobLauncherTestUtilsを使ってジョブを実行しています。
💬 JobLauncherTestUtilsは、Spring BatchのジョブをJUnitで手軽に起動・検証できる便利なユーティリティクラスです。
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ReplacementDataSet;
import org.dbunit.dataset.excel.XlsDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.junit.jupiter.api.Test;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
public class AAAAATest {
  private static final String TEST_DATA_DIR = "./src/test/resources/";
  // DB接続情報(本番では外部ファイルで管理推奨)
  private static final String DB_URL = "jdbc:oracle:thin:@localhost:1521:testdb";
  private static final String DB_USER = "testUser";
  private static final String DB_PASS = "testPassword";
  @Autowired
  @Qualifier("AAAAATest") 
  Job job;
  @Autowired
  JobLauncher jobLauncher;
  @Autowired
  JobRepository jobRepository;
  public JobLauncherTestUtils testUtils() {
    JobLauncherTestUtils jobLauncherTestUtils = new JobLauncherTestUtils();
    jobLauncherTestUtils.setJob(job);
    jobLauncherTestUtils.setJobLauncher(jobLauncher);
    jobLauncherTestUtils.setJobRepository(jobRepository);
    return jobLauncherTestUtils;
  }
  @Test
  void テストケース1() throws Exception {
    setupDatabaseWith("TestData_case1.xlsx");
    JobExecution execution = testUtils().launchJob();
    //実行結果が正常であること
    assertThat(execution.getExitStatus()).isEqualTo(ExitStatus.COMPLETED);
  }
  @Test
  void テストケース2() throws Exception {
    setupDatabaseWith("TestData_case2.xlsx");
    JobExecution execution = testUtils().launchJob();
    //実行結果が正常であること
    assertThat(execution.getExitStatus()).isEqualTo(ExitStatus.COMPLETED);
  }
  // 必要に応じて他のテストケースを追加…
  private void setupDatabaseWith(String fileName) throws Exception {
    try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS)) {
      IDatabaseConnection dbconn = new DatabaseConnection(conn);
      IDataSet dataSet = createExcelDataSet(TEST_DATA_DIR + fileName);
      DatabaseOperation.CLEAN_INSERT.execute(dbconn, dataSet);
    }
  }
  private IDataSet createExcelDataSet(String filePath) throws IOException {
    try {
      ReplacementDataSet dataSet = new ReplacementDataSet(new XlsDataSet(new File(filePath)));
      dataSet.addReplacementObject("null", null);
      return dataSet;
    } catch (Exception e) {
      throw new RuntimeException("Excelファイルの読み込みに失敗しました: " + filePath, e);
    }
  }
}
まとめ
✅ @Beforeを使うべきとき
- テストの共通初期化が必要なとき
 - データがどのテストでも同一である場合
 - 共通ロジックのモックやDI設定を簡略化したいとき
 
🚫 @Beforeを避けるべきとき
- 各テストケースで異なる入力データを使いたいとき
 - テスト間の依存を完全に断ちたいとき
 - 外部ファイル(Excelなど)でデータを明示的に管理したいとき
 
💡 おすすめの構成
- テストデータをExcelで管理(DBUnitで読み込み)
 - 各テストメソッドで必要なデータを個別にロード
 - テスト名とファイル名を対応させて、メンテナンス性を向上
 
🧭 まとめの一言
@Beforeは便利な反面、テストの独立性を損なう危険性もあります。
そのため、**「何を共通化し、何を独立させるか」**を意識したテスト設計が重要です。
DBUnitとExcelの活用で、再現性と保守性の高いテスト環境を構築しましょう 💪
Discussion