環境
- mybatis-spring-boot-starter: 1.3.1
- mybatis: 3.4.5
- mybatis-spring-boot-starter-test: 1.3.1
- postgresql jdbc : 42.1.4
- Spring Boot 1.5.9
- Java8
- PostgreSQL 9.6
やりたいこと
MyBatisを使ってDBにアクセスしています。
今、HotelDao.java
のfindById
メソッドのテストを実施したいです。
@Component
public class HotelDao {
private final SqlSession sqlSession;
public HotelDao(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
public Hotel findById(long id) {
return this.sqlSession.selectOne("findHotelById", id);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo2.mybatis.mapper.HotelMapper">
<select id="findHotelById" resultType="com.example.demo2.mybatis.domain.Hotel">
select * from hotel where city = #{id}
</select>
</mapper>
問題
以下のような、findById
メソッドを確認するテストコードを作成しました。
@RunWith(SpringRunner.class)
@MybatisTest
@Import({HotelDao.class})
public class HotelDaoTest {
@Autowired
private HotelDao hotelDao;
@Test
public void test() {
Hotel hotel = hotelDao.findById(1);
System.out.println(hotel);
//assert
}
}
JUnitで実行したら、以下のエラーが発生しました。
Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2018-01-24 00:24:03.507 ERROR 46308 --- [ main] o.s.boot.SpringApplication : Application startup failed
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'com.example.demo2.mybatis.dao.HotelDao':
Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'sqlSessionTemplate' defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]:
Unsatisfied dependency expressed through method 'sqlSessionTemplate' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'sqlSessionFactory' defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]:
Unsatisfied dependency expressed through method 'sqlSessionFactory' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'dataSource': Invocation of init method failed; nested exception is java.lang.IllegalStateException:
Failed to replace DataSource with an embedded database for tests. If you want an embedded database please put a supported one on the classpath or tune the replace attribute of @AutoconfigureTestDatabase.
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
...
※読みやすくするため、適当な箇所に改行を入れました。
原因
エラーの最後の方に、「Failed to replace DataSource with an embedded database for tests. If you want an embedded database please put a supported one on the classpath or tune the replace attribute of @AutoconfigureTestDatabase.」と記述されています。
書いてある内容は、
- DataSourceをテスト用の組み込みデータベースに置き換えられなかった。
- 組み込みデータベースを使いたいなら、サポートされている組み込みデータベースをクラスパスに追加するか、
@AutoconfigureTestDatabase
のreplace
属性を調整。
です。
@MyBatisTest
を付与すると、デフォルトでは組み込みデータベースを設定します。しかし今のプロジェクトでは、組み込みデータベース用の設定(pom.xmlに定義していない)を行っていないので、エラーが発生しているようです。
The @MybatisTest can be used if you want to test MyBatis components(Mapper interface and SqlSession). By default it will configure MyBatis(MyBatis-Spring) components(SqlSessionFactory and SqlSessionTemplate), configure MyBatis mapper interfaces and configure an in-memory embedded database.
※ http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-test-autoconfigure/ 引用
解決1(@AutoConfigureTestDatabase
を設定)
テスト時にPostgreSQLを使う場合の対応方法です。
@AutoConfigureTestDatabase(replace = Replace.NONE)
を追加しました。
@RunWith(SpringRunner.class)
@MybatisTest
@AutoConfigureTestDatabase(replace = Replace.NONE) //追加
@Import({HotelDao.class})
public class HotelDaoTest {
@Autowired
private HotelDao hotelDao;
@Test
public void test() {
Hotel hotel = hotelDao.findById(1);
System.out.println(hotel);
}
}
以下のサイトを参考にしました。
- Using a real database - MyBatis
- Spring-boot-starter-test cannot run database integration test
- Sprint Boot 1.4 @DataJpaTest - Error creating bean with name 'dataSource'
@AutoconfigureTestDatabase
について
@AutoconfigureTestDatabase
のパッケージ
Spring Boot 1.5.9では、@AutoconfigureTestDatabase
が2種類あります。
org.springframework.boot.test.autoconfigure.orm.jp
org.springframework.boot.test.autoconfigure.jdbc
*.orm.jp
の方は非推奨なので、*.jdbc
の方を使います。
解決2(テスト時は組み込みデータベースを利用)
HSQLDBを利用します。
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
テストデータを作成するSQLをsrc/test/resource/
直下に置きます。
そうすると、テスト実行前にこのSQLが実行されます。
CREATE TABLE hotel
(
city integer NOT NULL ,
name character varying(256),
address character varying(256),
zip character varying(256),
CONSTRAINT pkey PRIMARY KEY (city)
);
insert into hotel(city, name, address, zip) values (1, 'Conrad Treasury Place', 'William & George Streets', '4001')
補足
組み込みデータベースについて
アプリケーションに組み込まれたデータベース。事前にデータベースを用意する必要がなく、アプリケーションの起動時にデータベースが構築されます。
Springでのデータベースの初期化
schema.sql
だけでなく、data.sql
というファイル名でも、自動的に実行されます。
Spring Boot can automatically create the schema (DDL scripts) of your DataSource and initialize it (DML scripts): it loads SQL from the standard root classpath locations schema.sql and data.sql, respectively.