MyBatis
spring-boot
問題解決

【問題解決】MyBatisのテストで、「No qualifying bean of type~」というエラーが発生

環境

  • 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.javafindByIdメソッドのテストを実施したいです。

HotelDao.java
@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);
    }

}

問題

以下のような、findByIdメソッドを確認するテストコードを作成しました。

HotelDaoTest.java
@RunWith(SpringRunner.class)
@MybatisTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
public class HotelDaoTest {

    @Autowired
    private HotelDao hotelDao;

    @Test
    public void test() {
        Hotel hotel = hotelDao.findById(1);
        System.out.println(hotel);
    }

}

JUnitでテストメソッドを実行すると、以下のエラーがコンソールに表示されました。

console
2018-01-24 23:03:54.990 ERROR 22456 --- [           main] o.s.test.context.TestContextManager      : Caught exception while allowing TestExecutionListener [org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@6a472554] to prepare test instance [com.example.demo2.mybatis.dao.HotelDaoTest@275710fc]

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.demo2.mybatis.dao.HotelDaoTest': 
Unsatisfied dependency expressed through field 'hotelDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type 'com.example.demo2.mybatis.dao.HotelDao' available: expected at least 1 bean which qualifies as autowire candidate. 
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
...

※読みやすくするため、適切な箇所に改行を入れました

原因

エラーの最後の方では「No qualifying bean of type '~.HotelDao' available: expected at least 1 bean which qualifies as autowire candidate. 」、すなわち「HotelDaoのbeanが見つからない」と言われています。

@MyBatisTestを付与すると、@Componentのbeanはロードされないため、beanが見つからないようです。

Also regular @Component beans will not be loaded into the ApplicationContext.

http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-test-autoconfigure/ 引用

解決

@Importを使って、HotelDaoのbeanをロードしました。

HotelDaoTest.java
@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);
    }

}

http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-test-autoconfigure/#Test_for_DAO_pattern: 参考

補足

@Mapperの場合、@Importは不要

CityMapper.java
@Mapper
public interface CityMapper {
    @Select("select * from city")
    City findCity();
}
CityMapperTest.java
@RunWith(SpringRunner.class)
@MybatisTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
public class CityMapperTest  {

    @Autowired
    CityMapper cityMapper;

    @Test
    public void test() {
        City city = cityMapper.findCity();
        System.out.println(city);
    }

}

参考にしたサイト