はじめに
前から同僚にこの組み合わせだとテスト実施後のRollbackが上手くいかんと言われてました。
その時はJunit4使うことで解決したのですが、この度同じ組み合わせでなんとかする必要出てきたのと、これに時間使える状況だったのもあり頑張って解決した時のメモです。
環境
Java 11.0.3
Spring Boot 2.2.0.M4
doma-spring-boot-starter 1.1.0
spring-test-dbunit 1.3.0
dbunit 2.6.0
データベースはMariaDBを使っていますが、他のRDBでも特に問題ないと思います(未検証)。
pom.xml
必要そうなdependencyを載せておきます。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.seasar.doma.boot</groupId>
<artifactId>doma-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.springtestdbunit</groupId>
<artifactId>spring-test-dbunit</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.6.0</version>
<scope>test</scope>
</dependency>
</dependencies>
テストコードを書く前の準備
いくつかBeanを作成する必要があるため、コードを書いていきます。
サードパーティーのDBのTransactionをSpring側管理出来るようにするため、TransactionAwareDataSourceProxy
をDataSourceに設定します。
これは普通に起動された場合にも適応したいので、main側に記述します。
@Configuration
public class DatabaseConfig {
@Bean
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);
}
}
DaoとEntityも書く必要があるので、テストで使用するテーブルに合わせて実装します。
実際はDoma-genを使ったのですが、今回の話題とは別なので割愛します。
import org.seasar.doma.Column;
import org.seasar.doma.Entity;
import org.seasar.doma.GeneratedValue;
import org.seasar.doma.GenerationType;
import org.seasar.doma.Id;
import org.seasar.doma.Table;
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return role;
}
public void setName(String name) {
this.name = name;
}
}
import java.util.Optional;
import org.seasar.doma.Dao;
import org.seasar.doma.Delete;
import org.seasar.doma.Insert;
import org.seasar.doma.Select;
import org.seasar.doma.Update;
import org.seasar.doma.boot.ConfigAutowireable;
import com.tasogarei.User;
@Dao
@ConfigAutowireable
public interface UserDao {
@Select
Optional<User> selectById(Long id);
@Insert
int insert(MUser entity);
@Update
int update(User entity);
@Delete
int delete(User entity);
}
Domaの場合はSQLファイルも必要です(これもDoma-genで自動生成)
/src/mainresources/META-INF/
配下にパッケージ名でフォルダ掘ってそこに入れます。
select
*
from
user
where
id = /* id */1
あと、今回はXLSXからテストデータを読み込むので、Excelで読み込むデータを作成しています。
面倒という理由でここではファイルについては割愛します。
テストコードを書いていく
準備が出来たのでテストを書いていきます。
今回はDAOを直接コールしてその結果を確認するようなテストとします。
設定的にはほぼSpring Boot + Junit5の設定と変わりません。
変わる箇所は@TestExecutionListeners
くらいなものでしょうか。
Excelファイルからデータを入れる場合は@DbUnitConfiguration
も必要となります。
中身はこちらを参考に実装しました。
あとはテストメソッドに@DatabaseSetup
を付与して読み込むファイルを記述するだけです。
classpath
は/src/test/resources
を指しています。
import static org.junit.jupiter.api.Assertions.*;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;
import com.github.springtestdbunit.TransactionDbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import com.tasogarei.UserDao;
import com.tasogarei.User;
import com.tasogarei.XlsDataSetLoader;
@ExtendWith(SpringExtension.class)
@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionDbUnitTestExecutionListener.class
})
@DbUnitConfiguration(dataSetLoader = XlsDataSetLoader.class)
@Transactional
public class DBUnitTest {
@Autowired
private UserDao userDao;
@Test
@DatabaseSetup("classpath:dataset/demo-test.xlsx")
public void test() {
Optional<User> user = userDao.selectById(2L);
assertTrue(user.isPresent());
}
}
終わりに
書いて見返したらたいして特別な設定をしてたわけではありませんが、次やった時に困らないように残しておきます。
今、Doma使っているけど、大変なのであんまり使いたくはないのですが。