【Springboot×DBUnit】DBを絡めたテストの設定
毎度ながら忘れる。。。
データのインポートはcsv使います。公式ではXMLでの記載しか書いてないですけど、XMLは面倒なんです。
環境
springboot 1.5.x
DBUnit2.6
DBUnit公式
まずは何より公式をチラ見しましょう。
参考
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
}
}
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;
}
}
参考:空文字投入パターン
こんな感じで楽しい単体テストライフを過ごしましょう~
この記事が気に入ったらサポートをしてみませんか?