以前のポスト Spring Boot, Spock, DBUnit でトランザクションを使ったテスト でも触れたように DbSetup では、本日現在 (2016-12-11)、テストデータのセットアップ処理でコミット処理まで実施してしまう作りになっている。
リファレンスを確認しても、DbSetup#launch()
を使用したテストデータのセットアップ方法にしか触れられていない。
http://dbsetup.ninja-squad.com/user-guide.html
ただし、ソースを確認すれば、DbSetup#launch()
によるセットアップ処理は非常にシンプルなものであり、問題のコミット処理についてもこれを避けた記述が可能であることがわかるため、今回は DbSetup を使用した場合の、トランザクションを有効にしたテストの記述方法を書き残しておく。
環境
- Java 1.8.0_91
- Maven 3.3.9 (Maven wrapper)
- Spring Boot 1.4.0.RELEASE
- Groovy 2.4.7
- Spock 1.1-groovy-2.4-rc-3
- DbSetup 2.1.0
$ ./mvnw -version
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T01:41:47+09:00)
Maven home: /Users/yo1000/.m2/wrapper/dists/apache-maven-3.3.9-bin/2609u9g41na2l7ogackmif6fj2/apache-maven-3.3.9
Java version: 1.8.0_91, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "mac os x", version: "10.11.5", arch: "x86_64", family: "mac"
依存関係
Spring Boot によるテスト、Spock、DBUnit それぞれを動作させるために必要なものを一通り挙げると以下のような感じ。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.4.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4-rc-3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.1-groovy-2.4-rc-3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.ninja-squad</groupId>
<artifactId>DbSetup</artifactId>
<version>2.1.0</version>
<scope>test</scope>
</dependency>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<goals>
<goal>addTestSources</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<sources>
<fileset>
<directory>${pom.basedir}/src/test/groovy</directory>
<includes>
<include>**/*.groovy</include>
</includes>
</fileset>
</sources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<includes>
<include>**/*Test.java</include>
<include>**/*Spec.java</include>
<include>**/*Tests.java</include>
<include>**/*Specs.java</include>
</includes>
</configuration>
</plugin>
テスト
ここからは実際の書き方について。行うことは以下の3つです。
-
TransactionAwareDataSourceProxy
を使用してDataSource
をラップする。 - テスト終了時にロールバックしたいテストケースに
@Transactionl
を指定する。 - テストデータの セットアップに
DbSetup#launch()
を使用せず、Operation#execute(Connection, BinderConfiguration)
を使用する。
その他は、至って普通のテストです。以下のような使い方になるかと思います。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
@Autowired
public DataSource dataSource(DataSourceProperties dataSourceProperties) {
DriverManagerDataSource dataSource = new DriverManagerDataSource(
dataSourceProperties.getUrl(),
dataSourceProperties.getUsername(),
dataSourceProperties.getPassword()
);
dataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
dataSource.setSchema(dataSource.getSchema());
return new TransactionAwareDataSourceProxy(dataSource);
}
}
@Unroll
@SpringBootTest
class TransactionalServiceSpec extends Specification {
@Autowired
DataSource dataSource
@Transactional
def "テスト終了時にテストデータとテスト対象による変更をロールバック"() {
setup:
// テストデータの挿入
def destination = new DataSourceDestination(dataSource)
def operation = Operations.insertInto(..)
/*
* ここが通常の DbSetup とは異なる書き方
*/
def connection = destination.connection;
connection.autoCommit = false
operation.execute(connection, DefaultBinderConfiguration.INSTANCE)
when:
// テスト対象を実行
then:
// テーブルの内容を検証
assert ..
}
@Transactional
def "テスト終了時にテスト対象による変更をロールバック"() {
when:
// テスト対象を実行
then:
// テーブルの内容を検証
assert ..
}
}
以上のような書き方で、DbSetup でも、トランザクションを有効にしたテストの記述と行うことができるようになります。
やむなくデータベースに蓄積されたデータに依存したテストを書かなければならない場合などには、データの保全はとても重要になってくるため、このような書き方があることは抑えておきたいところですね。