見出し画像

【Springboot×DBUnit】DBを絡めたテストの設定

毎度ながら忘れる。。。
データのインポートはcsv使います。公式ではXMLでの記載しか書いてないですけど、XMLは面倒なんです。

環境

springboot 1.5.x
DBUnit2.6

DBUnit公式

まずは何より公式をチラ見しましょう。

DBUnit

参考

SpringBootでDBも絡めた単体テストを書いてみる

build.gradle

testCompile group: 'com.github.springtestdbunit', name: 'spring-test-dbunit', version: '1.3.0'
testCompile group: 'org.dbunit', name: 'dbunit', version: '2.6.0'

eclipse上だと、依存を追加するだけで良いが、Jenkinsなどでgradleタスクを実行する場合だと、出力先ディレクトリが変わるので、出力先のをclassesに変える以下も追記する。dependenciesの下辺りに書く。

sourceSets {
	test {
		output.resourcesDir = output.classesDir
	}
}

参考:DBUnitがリソースを読み込めない

DB周りの設定(test.properties)

本番はMySQLを使ってるけど、うっかり間違ってコミットしちゃったりすると危ないので、ローカルやテストのときはインメモリのH2を使うようにしてます。DBUnitでもロールバックとかはあるけど、いちいちつなげるのも面倒なので、インメモリにしとくと起動も速くて便利。

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=MYSQL;
spring.datasource.username=sa
spring.datasource.password=sa

テストクラス①

お待ちかねのテストクラス。
なんかいろいろアノテーションと読み込むリスナークラスを追加していく。
webEnviromentとかはプロジェクトのテストの環境によったりするので、よしなに。
ちなみに、全テストケースに追加するのはちょっとつかれるので、うちではAbstractクラス使ってそれをテストケースクラスに継承させるようにしてます。楽しようぜ。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestApplication.class)
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
      DirtiesContextTestExecutionListener.class,
     TransactionalTestExecutionListener.class,
      DbUnitTestExecutionListener.class })
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@TestPropertySource(locations = "/test.properties")
@Transactional
@DbUnitConfiguration(dataSetLoader = CsvDataSetLoader.class)
public abstract class AbstractUsingDBServiceTest {

CsvDataSetLoader.java

さっきも言いましたが、公式のチュートリアルはXMLでデータをインポートさせる方法しか書いてないので、CSVを読めるようにします。そのためのクラス。

import java.net.URL;

import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.csv.CsvURLDataSet;
import org.springframework.core.io.Resource;

import com.github.springtestdbunit.dataset.AbstractDataSetLoader;

public class CsvDataSetLoader extends AbstractDataSetLoader {

	@Override
	protected IDataSet createDataSet(Resource resource) throws Exception {
		String path = resource.getURL().toString();
		// なぜかmainパッケージで来るのでtestに置き換える
		path = path.replace("main", "test");
		return new CsvURLDataSet(new URL(path));
	}

}

ここのResourceがなんでmainのパスで来るのかは謎。いろいろやってみたけど、めんどくさくなってtestにリプレイスする作戦で今の所うまくいってます。

このクラスを追加するとコンパイルは通るはず。

テストクラス②

@Test
@DatabaseSetup(value = "/jp/co/test/service/test/")
public void testSetFormData() {

テストデータがあるディレクトリパスを @DatabaseSetup に渡すだけ。なんて便利。

テストデータディレクトリ

src/test/resources
└─jp
   └─co
       └─test
           └─service
               └─test
                       client.csv
                       client_detail.csv
                       table-ordering.txt

だいたいこんな感じ。
table-ordering.txtに読み込みたいテーブル名を改行で区切りながら書いておくとそのテーブルとデータを自動的にcreate/importしてくれる。
読み込むのは一番上から順番。

client
client_detail

ここまでやると、テストを実行すると、基本的な動きはできるはず。

おまけ

java.lang.IllegalArgumentException: table.column=person.person_name value is empty but must contain a value (to disable this feature check, set DatabaseConfig.FEATURE_ALLOW_EMPTY_FIELDS to true)

データに空文字が入ってる場合は、こんなエラーを吐いてくることもあるので、空文字を許可するように設定する。が、ちょっとひと手間必要。Configクラスを一つ、testパッケージ内で良いので、作ってあげる。

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.github.springtestdbunit.bean.DatabaseConfigBean;
import com.github.springtestdbunit.bean.DatabaseDataSourceConnectionFactoryBean;

@Configuration
public class DataSourceConifg {

	@Bean
	public DatabaseConfigBean dbUnitDatabaseConfig() {
		DatabaseConfigBean bean = new DatabaseConfigBean();

		bean.setAllowEmptyFields(true); // ここ

		return bean;
	}

	@Bean
	public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnection(DatabaseConfigBean dbUnitDatabaseConfig,
			DataSource dataSource) {
		DatabaseDataSourceConnectionFactoryBean bean = new DatabaseDataSourceConnectionFactoryBean(dataSource);
		bean.setDatabaseConfig(dbUnitDatabaseConfig);
		return bean;
	}
}

参考:空文字投入パターン

こんな感じで楽しい単体テストライフを過ごしましょう~

この記事が気に入ったらサポートをしてみませんか?