山崎屋の技術メモ

IT業界で働く中でテクノロジーを愛するSIerのシステムエンジニア👨‍💻 | AndroidとWebアプリの二刀流🧙‍♂️ | コードの裏にあるストーリーを綴るブログ執筆者✍️ | 日々進化するデジタル世界で学び続ける探究者🚀 | #TechLover #CodeArtisan、気になること、メモしておきたいことを書いていきます。

【DbUnit】テスト完了時にテーブルデータを元に戻す方法

前回 SpringBoot で作成した DB 操作クラスに対し DbUnit を使って簡単なテスト実施方法を紹介しました。
www.shookuro.com


前回の記事にも書きましたが、この自動テストの実行後にはテーブルのデータがテストで使用したデータに変わってしまいます。ちょっと困りますよね。

今回の記事では SpringBoot で DbUnit を使い、テスト完了時にテーブルデータをテスト実行前の状態に戻す方法について書いていきたいと思います。

DBバージョン は postgresql 9.5。SpringBootは 2.1.2。DBUnit は 2.6.0 です。

結論

テストのときは DataSource を TransactionAwareDataSourceProxy クラスでラップして Spring コンテナに Bean 登録します。

そして @Transactional アノテーションをテストクラスに付与し、トランザクション内でテストが実行されるようにします。

TransactionAwareDataSourceProxy とは

JavaDoc:
TransactionAwareDataSourceProxy (Spring Framework 5.0.6.BUILD-SNAPSHOT API)

簡単に言うと通常の DataSource への操作を中継してくれる DataSource です。このクラス自体も javax.sql.DataSource を impliments しています。

これを利用することにより、テストで実行される各トランザクションをまとめて大きな一つのトランザクションとして扱えるようにします。各トランザクションで Commit が行われたとしても、その外側の大きなトランザクションで Rollback すれば全体の変更が取り消されるということです。

実践編

(以降で記載している具体的なソースの内容は前回の記事を参照してください。)
DBUnit を使って Excel からデータを DB にロードする with Spring Boot - 山崎屋の技術メモ

テスト用 Configuration の作成

今回はサンプルなのでテストクラスと同じ階層に SampleTestConfiguration というクラスを作成しました。
f:id:yyama1556:20190126180832p:plain

実際のプロジェクトでは設定クラス用のパッケージを作ったほうが良いでしょう。

クラスの中身は次のように DataSourceBuilder でデータソースを作って TransactionAwareDataSourceProxy クラスのコンストラクタに引数で渡します。

package org.yyama;

import javax.sql.DataSource;

import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;

public class SampleTestConfiguration {
	@Bean
	public DataSource dataSource() {
		return new TransactionAwareDataSourceProxy(
			DataSourceBuilder
			.create()
			.username("postgres")
			.password("postgres")
			.url("jdbc:postgresql://localhost:5432/postgres")
			.driverClassName("org.postgresql.Driver")
			.build());
	}
}

クラスに @Component を付与してはいけません。テスト時以外の実行時にも DataSource に TransactionAwareDataSourceProxy が使用されてしまいます。
 

テストクラスで テスト用 Configuration を利用する

テストクラスで @Import を使って先ほど作成したテスト用 Configuration を読み込みます。

クラス宣言のあたりが

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

だったのを、

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@Import(SampleTestConfiguration.class)
public class SampleTest_proc {
・
・
・

にします。

加えて、ユニットテスト内の DB アクセスを大きなトランザクションで囲むため、@Transaction も付与します。こうなります。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@Import(SampleTestConfiguration.class)
@Transactional
public class SampleTest_proc {
・
・
・

これでユニットテスト完了時にテーブルデータが元の状態に戻るようになったはずです。
 
 
いちおう動作確認は欠かせません。

テスト前のテーブルの状態をこうしました。

postgres=# select * from member;
 id |  name   | age
----+---------+-----
 49 | yyama   |  25
 50 | ryotsu  |  38
 51 | akimoto |  24
 52 | bucho   |  55
(4 行)

そしてテスト実行!
グリーン!!
 
そしてテーブルの中身は、、、

postgres=# select * from member;
 id |  name   | age
----+---------+-----
 49 | yyama   |  25
 50 | ryotsu  |  38
 51 | akimoto |  24
 52 | bucho   |  55
(4 行)

テスト前と同じ!OK!!
 
自分でも勉強しながらやっているので、書いていることが本当なのかけっこう不安でしたw。

というわけで今回は成功です。

お疲れ様でした。

ユニットテスト完了時にテーブルデータを元に戻す方法まとめ

テスト時には DataSource を TransactionAwareDataSourceProxy でラップし、テストケースを大きなトランザクションとして実行し、テスト終了時には全てを Rollback することで、テスト前のデータ状態に戻す方法を紹介しました。

でわ!

Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発

Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発

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

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

テスト駆動開発

テスト駆動開発