[Test]@DataJpaTest 와 @Import // (Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.kinderlabs.posadmin.application.mapper.StoreInfoMapper]: Specified class is an interface) 에러 해결

백승호·2022년 10월 13일
0

약식 DDD구조의 application 계층 테스트 코드를 작성하던 중 @SpringBootTest를 통해 테스트를 하게 되면 매번 서버를 올렸다 내리는 것이 테스트의 효율성을 저하시키는 것 같았습니다.

그래서 사용해보기로 한 것이 @DataJpaTest 입니다.

document에 나온 @DataJpaTest에 대한 설명은 이렇습니다.

@DataJpaTest

Annotation for a JPA test that focuses only on JPA components.
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to JPA tests.

By default, tests annotated with @DataJpaTest are transactional and roll back at the end of each test. They also use an embedded in-memory database (replacing any explicit or usually auto-configured DataSource). The @AutoConfigureTestDatabase annotation can be used to override these settings.

SQL queries are logged by default by setting the spring.jpa.show-sql property to true. This can be disabled using the showSql attribute.

If you are looking to load your full application configuration, but use an embedded database, you should consider @SpringBootTest combined with @AutoConfigureTestDatabase rather than this annotation.

When using JUnit 4, this annotation should be used in combination with @RunWith(SpringRunner.class).

대충 JPA test시 JPA components로 등록된 것만 접근해서 @SpringBootTest 처럼 full auto-configuration을 하지 않는 다는 말입니다. 추가로 @DataJpaTest 사용시 @Transactional 과 @RollBack도 지원해준다고 하는군요.


바로 본론으로 넘어가서 위와 같이 테스트코드 관련 어노테이션을 적용했을 때 아래와 같은 문제가 터졌습니다

Caused by: org.springframework.beans.BeanInstantiationException: 
Failed to instantiate [com.kinderlabs.posadmin.application.mapper.StoreInfoMapper]: 
Specified class is an interface

물론 상단엔 관련된 수많은 에러가 있었지만 핵심은 이것이었습니다.

문제 상황

@Autowired로 StoreInfoService라는 인터페이스를 DI 시켰습니다. application 계층이 아닌 다른 계층에 있는 인터페이스이기 때문에 구현체인 StoreInfoServiceImpl도 @Import로 가져왔습니다.

그런데 위와 같은 에러가 발생했습니다.

@Autowired로 주입한 StoreInfoService를 갖고오면 안 되는건가 싶어서 구현체인 StoreInfoServiceImpl을 주입하는 것으로 바꿔봤고 관련된 컴포넌트들을 다 import했습니다.
그래도 에러는 해결되지 않았습니다.

그럼 뭐가 문제일까..?

문제는 @Autowird한 인터페이스에 있는 것이 아니라 @Import로 가져온 리스트 안에 있었습니다.

해결

간단합니다. @Import안에 StoreInfoMapper라는 인터페이스가 있는데 이것을 구현체로 바꿔줬습니다.

위와 같이 StoreInfoMapperImpl을 import했더니 해결됐습니다.

@Autowired로 주입한 것은 interface여도 상관 없습니다!!

결론

테스트코드 작성시 @Import로 관련된 클래스들을 가져올 땐 인터페이스는 하나라도 넣지 말자!

profile
처음처럼

0개의 댓글