일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 프리코스
- 의존성
- 트랜잭션
- 서블릿
- REDIS
- AOP
- Spring Batch
- JPA
- 백준
- CircuitBreaker
- MSA
- 자바
- 우아한테크코스
- 우아한세미나
- HTTP
- 우테코
- 스프링부트
- Paging
- 스프링 부트
- Level2
- Docker
- 프로그래머스
- 세션
- 레벨2
- 코드리뷰
- yml
- mock
- JUnit5
- AWS
- 미션
- Today
- Total
늘
Junit5 테스트 동작 방식과 빈 주입 본문
@JdbcTest
@Sql("/schema.sql")
class RoomDaoTest {
@Autowired
private JdbcTemplate jdbcTemplate;
private RoomDao roomDao = new RoomDaoImpl(jdbcTemplate);
}
위 코드는 현재 NPE가 발생합니다.
반면에 아래 코드처럼 텍스트픽쳐스를 이용한 테스트는 정상 동작합니다.
@Sql("/schema.sql")
@JdbcTest
class PieceDaoTest {
@Autowired
private JdbcTemplate jdbcTemplate;
private PieceDao pieceDao;
@BeforeEach
void setUp(){
pieceDao = new PieceDaoImpl(jdbcTemplate);
}
}
JdbcTemplate은 빈으로 등록되어서 싱글톤으로 만들어져 있습니다.
반면에 Junit 테스트는 각 테스트 메서드마다 TestClass의 인스턴스를 만들고 각 인스턴스가 생성된 후 테스트가 실행한다고 합니다.
그렇기때문에 빈 객체에 대해서 스프링 IoC로 인해 개발자가 직접 인스턴스를 생성하지 않고 스프링이 관리해주는데, Junit 테스트 동작 방식이 각 테스트 메서드마다 필드에 선언된 객체에 대해서 직접 인스턴스를 생성하기 때문에 빈으로 관리되지 않아서, 빈 의존성 주입받는 게 실패해서 발생한 것이라고 추측을 한다.
class Sample {
private JdbcTemplate jdbcTemplate;
private RoomDao roomDao = new RoomDaoImpl(jdbcTemplate); // 1번
public Sample() { } // 2번
public setJdbcTemplate(JdbcTemplate jdbcTemplate) { // 3번
this.jdbcTemplate = jdbcTemplate;
}
}
class SampleApplication {
public static void main(String args) {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
Sample sample = new Sample();
sample.setJdbcTemplate(jdbcTemplate);
}
}
이런 코드가 있다고 할 때, Sample 클래스에 있는 1~3번 코드의 실행 순서가 어떻게 될까요?위 내용을 먼저 생각해보신 후, 아래 코드를 다시 한번 보면 좋겠네요.
1,2,3번 순서대로 실행이 되었다. -> 모든 필드가 초기화 되고 그 후 생성자가 불러오는 것 같다
@JdbcTest
@Sql("/schema.sql")
class RoomDaoTest {
@Autowired
private JdbcTemplate jdbcTemplate;
private RoomDao roomDao = new RoomDaoImpl(jdbcTemplate);
jdbcTemplate 을 먼저 주입받고, 그 후에 RoomDao 를 생성하려면 어떻게 하면 좋을지 고민해볼 수 있겠죠.
jdbcTemplate 이 RoomDaoTest 에서 필요한 것인지, RoomDao 를 만들기 위해서만 필요한 것인지도 고민해볼 수 있을 것 같네요.
그렇기때문에 bean 객체에 대해서 스프링 IoC로 인해 개발자가 직접 인스턴스를 생성하지 않고 스프링이 관리 해주는데, Junit 테스트 동작 방식이 각 테스트 메서드마다 필드에 선언된 객체에 대해서 직접 인스턴스를 생성하기 때문에 빈으로 관리 되지 않아서, 빈 의존성 주입 받는게 실패해서 발생한 것이라고 봐도 될까요?
@Autowired
private JdbcTemplate jdbcTemplate;
private final RoomDao roomDao;
public RoomDaoTest(){
roomDao = new RoomDaoImpl(jdbcTemplate);
}
그래서
private JdbcTemplate jdbcTemplate;
private final RoomDao roomDao;
public RoomDaoTest(DataSource dataSource){
jdbcTemplate = new JdbcTemplate(dataSource);
roomDao = new RoomDaoImpl(jdbcTemplate);
}
위와 같이 생성자에서 받도록 실행을 했는데 생성자를 통해 주입하는 이 방식은 Junit5부터 안된다고 한다..
키워드는 Junit5 생성자 주입 에러라고 치면 나올것이다.
그런데 위 코드에서 생성자에 @Autowired만 붙이면 정상 동작이 되었다.
아무래도 Junit에서는 Jupiter가 빈들을 관리한다고 한다. 그래서 @Autowired를 명시적으로 적지 않으면 해당 스프링 빈을 찾지 못하므로 @Autowired를 적어서 스프링에게 해당 빈을 찾으라고 알려줘야 작동하는 것으로 보인다.
빈이 생성된 이후 추가로 호출되는 콜백들이 있는데요. Spring bean lifecycle, Spring bean hook 같은 키워드로 검색해보시면 도움이 될 것 같아요!추후에는 위 2개의 키워드도 찾아봐서 정리하려고 한다.
정리
필드에서 바로 주입받으려면 생성자가 실행된 이후에 일어나는 거라고 생각해서 필드 주입이 아닌 생성자 주입을 이용해야한다.
이때 Junit에서는 Jupiter가 빈들을 관리한다고 한다. 그래서 @Autowired를 명시적으로 적지 않으면 해당 스프링 빈을 찾지 못하므로 @Autowired를 적어서 스프링에게 해당 빈을 찾으라고 알려줘야 작동한다.
Reference
https://goodgid.github.io/How-JUnit-Works/
https://velog.io/@sdp1123/JUnit5-%EC%83%9D%EC%84%B1%EC%9E%90-%EC%A3%BC%EC%9E%85-%EC%98%A4%EB%A5%98
'우아한테크코스 4기' 카테고리의 다른 글
level 2 스프링 (0) | 2022.06.10 |
---|---|
리눅스 명령어와 권한 설정 chmod (0) | 2022.06.01 |
[Exception]checked Exception vs unchecked Exception (0) | 2022.04.25 |
우테코 Lv1 강의 정리 (0) | 2022.04.12 |
우아한 한 달 생활기 (0) | 2022.03.28 |