山崎屋の技術メモ

IT業界で働く中で、気になること、メモしておきたいことを書いていきます。

DBUnit を使って Excel からデータを DB にロードする with Spring Boot

DB 絡みのユニットテストを行う場合、テストケースごとにテーブルのデータを準備したいことがあると思います。

DBUnit を使えばあらかじめ用意しておいたデータをテストメソッドごとにテーブルにインポートしてからテストを実行できます。

用意しておくデータは csv、xml、Excel 形式が利用できます。

参考サイト:
DBUnitの導入とxml,Excel,CSVのサンプルプログラム(DBUnit):技術空間

Junit や SpringBoot を利用した DB 接続については過去記事で紹介していますので参考にしてください。
【JUnit入門】ユニットテストの基本 - 山崎屋の技術メモ
Spring boot 入門 DB 接続する簡単な Web アプリを作成 - 山崎屋の技術メモ


今回は Spring Boot で作成したアプリに DBUnit を利用利用する方法。その際、 Excel からテストデータをインポートする方法をメモしておきたいと思います。

DB は postgresql 9.5。SpringBootは 2.1.2。

テーブルの準備

次のようなテーブルを用意しました。

postgres=# \d member
                              テーブル "public.member"
  列  |          型           |                       修飾語
------+-----------------------+-----------------------------------------------------
 id   | integer               | not null default nextval('member_id_seq'::regclass)
 name | character varying(10) |
 age  | integer               |
インデックス:
    "member_pkey" PRIMARY KEY, btree (id)


テストデータの準備

 
Excelで次のようなブックを作成し「test-data.xlsx」というファイル名で保存しました。
f:id:yyama1556:20190120163129p:plain

シート名にはテーブル名を設定しておく必要があります。
 
このブックをプロジェクトのどこにおくかは悩みどころですが、小さいプロジェクトでしたらテストクラスと同じ場所でも良いのではないでしょうか。
 
 

pom.xml


DBUnit に直接関係ない設定もありますが、全量載せておきます。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.2.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>org.yyama</groupId>
	<artifactId>sample</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>sample</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.dbunit</groupId>
			<artifactId>dbunit</artifactId>
			<version>2.6.0</version>
		</dependency>
		<dependency>
			<groupId>com.atomikos</groupId>
			<artifactId>transactions-osgi</artifactId>
			<version>4.0.6</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

ごらんのとおり DBUnit のバージョンは 2.6.0 です。

テスト対象クラス

簡単な DB 接続するクラスを用意しました。クラス名は Sample としました。

package org.yyama;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class Sample {

	@Autowired
	private JdbcTemplate jdbcTemplate;

	// SQL
	private final String GET_NAME_OVER_20_AGE = "select * from member where age >= 20 order by id";

	public List<String> proc() {
		List<Map<String, Object>> list = jdbcTemplate.queryForList(GET_NAME_OVER_20_AGE);
		return list.stream().map(o -> (String) o.get("name")).collect(Collectors.toList());
	}
}

proc メソッドでテーブルを select し 20歳以上の人の名前をリストで返します。

最終的なプロジェクト構成は次のようになりました。
f:id:yyama1556:20190120163620p:plain

application.properties に DB 接続情報を記載しておくのも忘れないでください。以下サンプルです(環境によって変えてください)。

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=postgres


テストクラス

そしてテストクラスです。

package org.yyama;

import static org.junit.Assert.*;

import java.io.File;
import java.sql.Connection;
import java.util.List;

import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.excel.XlsDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class SampleTest_proc {

	@Autowired
	private JdbcTemplate jdbcTemplate;

	@Autowired
	private Sample sample;

	private void tableSetUp(String excelName) throws Exception {
		// DBコネクション取得
		Connection conn = jdbcTemplate.getDataSource().getConnection();
		IDatabaseConnection dbconn = new DatabaseConnection(conn);

		// Excel用データセット作成
		File f = new File(ClassLoader.getSystemResource(excelName).getFile());
		IDataSet dataset = new XlsDataSet(f);

		// データの全削除
		DatabaseOperation.DELETE_ALL.execute(dbconn, dataset);

		// データの挿入
		DatabaseOperation.INSERT.execute(dbconn, dataset);
	}

	@Test
	public void _20歳以上の人の名前が返ること() throws Exception {
		// 準備
		tableSetUp("org/yyama/test_data.xlsx");

		// 実行
		List<String> list = sample.proc();

		// 検証
		assertEquals(2, list.size());
		assertEquals("fuga", list.get(0));
		assertEquals("piyo", list.get(1));
	}

}


tableSetUp メソッドで テーブルにテスト用データを投入しています。@Before メソッドを使用して、テストごとに実行される準備メソッドでも良いのですが、テストケースによってデータの Excel を変えたい場合は、このように Excel ファイル名を渡す共通メソッドを準備しておくと便利です。

処理についてはコメントにあるとおりなので解説は省略させていただきます。
 

テーブルのデータは戻らない

このままだと、テストのたびにテーブルのデータがテスト用に変わってしまうという問題があります

実行前にこんなデータがあったとして、、

postgres=# select * from member;
 id |  name   | age
----+---------+-----
 42 | yyama   |  25
 43 | ryotsu  |  38
 44 | akimoto |  24
 45 | bucho   |  55
(4 行)

実行後、勝手に変えられています。

postgres=# select * from member;
 id | name | age
----+------+-----
  1 | hoge |  19
  2 | fuga |  20
  3 | piyo |  21
(3 行)

これを解決する方法は別記事にしました。
【DbUnit】テスト完了時にテーブルデータを元に戻す方法 - 山崎屋の技術メモ

Excel を使用した DBUnit の使い方まとめ

今回は Spring Boot で作成されたアプリを DBUnit でテストする方法、その際 Excel にテストデータを準備しておいて自動でテーブルデータを変更しつつテスト実行する方法を紹介しました。

それでは!

テスト駆動開発

テスト駆動開発

Java本格入門 ~モダンスタイルによる基礎からオブジェクト指向・実用ライブラリまで

Java本格入門 ~モダンスタイルによる基礎からオブジェクト指向・実用ライブラリまで

  • 作者: 谷本心,阪本雄一郎,岡田拓也,秋葉誠,村田賢一郎,アクロクエストテクノロジー株式会社
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/04/18
  • メディア: 大型本
  • この商品を含むブログを見る
JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)

JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)