Junit を使用したユニットテスト(自動テスト)の基本を以前記事にしました。
www.shookuro.com
今回は DB も含めた自動テストのやり方をメモしておきたいと思います。
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。DBUnit は 2.6.0。
テーブルの準備
次のようなテーブルを用意しました。
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」というファイル名で保存しました。
シート名にはテーブル名を設定しておく必要があります。
このブックをプロジェクトのどこにおくかは悩みどころですが、小さいプロジェクトでしたらテストクラスと同じ場所でも良いのではないでしょうか。
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歳以上の人の名前をリストで返します。
最終的なプロジェクト構成です。
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 にテストデータを準備しておいて自動でテーブルデータを変更しつつテスト実行する方法を紹介しました。
それでは!
JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)
- 作者:渡辺 修司
- 発売日: 2012/11/21
- メディア: 単行本(ソフトカバー)