[SpringBoot] test framework를 이용한 통합테스트

suRan·2022년 7월 26일
0

🍃 SpringBoot

목록 보기
9/24
post-thumbnail

테스트 클래스 생성

테스트 클래스 KdtSpringContextTests를 생성한다.

import org.springframework.test.context.ContextConfiguration;

@ContextConfiguration 을 이용하기 위해서는
test.context의 안에 있는 클래스를 import해야한다.

testcontext로 만들어진 applicationContext가 만들어져야 한다.
그렇게 만들어진 applicationContext
테스트 코드에서 @Autowired로 받아올 수 있다.

hamcrest 관련 패키지도 잊지 말고 import해준다.

코드

  • notNullValue()
    notNullValue()는 hamcrest의 매쳐 중 하나로

그런데 위 코드를 실행하면 결과는 아래와 같다.

결과

@ContextConfiguration는 어떤 식으로
applicationContext가 만들어져야 하는지만 알려줄 뿐
실질적으로 junit과 상호작용해서 applicationContext이 만들어지게 하려면
@ExtendWith()를 사용해야한다.

@ExtendWith()
junit5에서 제공하는 어노테이션

코드

결과

실제 applicationContext이 생성된 것을 확인 가능.

Junit5에서 동작하기 위해 @ExtendWith() 어노테이션을 함께 사용하면
실제 spring test framework를 사용할 수 있다.

내부적인 코드에 의해 test.context와 상호작용할 수 있게 되는 것이다.

내부에 생성된 applicationContext에서 @Bean을 가져와 보자.

코드

결과

applicationContextBean으로 등록되어 있지 않은 것을 확인할 수 있다.

@ContextConfiguration() 의 인자로
xml을 주면 xml기반의 bean을 불러올 수도 있고,
클래스를 주면 applicationContext에 대해 Bean definition을 한
클래스들 (Ex: AppConfiguration)을 주면 해당 클래스를 불러와서 읽고,
applicationContext를 만들어주는 것이다.

하지만 이 방법은 porfile 등 별도의 설정이 필요할 수 있기 때문에
이 방법을 쓰지 않고 별도의 `applicationConfiguration 클래스 파일을 만들어서 전달해줄 수도 있다.

테스트 패키지 폴더의 밑에 생성해줄 수도 있고,
테스트 클래스 내부에서만 사용한다면 내부에 static으로 정의해줄 수도 있다.

오류 !
@ContextConfiguration(classes = {AppConfiguration.class}) 코드의
AppConfiguration.class 에서 intellij가 AppConfiguration를 인식하지 못한다는
오류 안내가 나타났다. 테스트 코드인데 AppConfiguration클래스 import가 답이 될 리는 없으니
코드를 계속 비교해보다가 새로 만든 test클래스의 패키지 경로가 문제였다는 걸 깨달았다.
main의 java폴더에서 AppConfiguration클래스가 위치한 경로보다
하위 패키지 경로에 test클래스를 작성했기 때문에
코드에서 AppConfiguration클래스를 인지하지 못한 것 같다.
그래서 패키지 경로를 AppConfiguration클래스와 동일하게 맞춰주었다.

@ContextConfiguration에 별도로 Bean 설정을 정의한 클래스나 xml을 전달하지 않으면
기본적으로 클래스 내부의 @Configuration이 달린 static 클래스를 찾게 된다.

스프링에서는 조금 더 편리한 어노테이션을 제공해준다.

@SpringJUnitConfig를 사용하면

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppConfiguration.class )

위 두 코드를 하나의 코드로 작성할 수 있게 된다.
두 개의 코드에 인자로 전달했던 값을 그대로 @SpringJUnitConfig에게 전달할 수도 있다.

통합테스트

이전에는 Mock을 이용한 통합테스트를 진행했다면
이번에는 applicationContext에서 가져와서 테스트를 진행한다.

log 실습 시 사용했던
@ComponentScan( basePackages = {"org.prgrms.kdt.voucher", "org.prgrms.kdt.order"})
코드를 테스트 코드에 입력해준다.

그렇게 하면
voucher와 order에 대한 컴포넌트 스캔 진행 -> 각 서비스와 레포지토리가 빈에 등록된다.

이제 @Autowired로 테스트 대상인 OrderService를 가져와서 테스트를 진행한다.

applicationContext가 만들어질 때 bean이 wiring되면서 context가 등록되어있는 다른
VoucherRepository, OrderService와 의존관계가 resolve된 상태에서 OrderService가 테스트 클래스에 할당된 것이다. 이런 OrderService를 가지고 테스트를 진행할 수 있다.

Given, When, Then에 사용했던 코드를 활용할 수 있다.
그러나 몇몇 코드에는 수정이 필요하다.

예를 들어

voucherRepository를 추가할 때
var voucherRepository = new MemoryVoucherRepository();
와 같은 코드 대신

@Autowired
VoucherRepository voucherRepository;

으로 추가해줄 수도 있을 것이다.

(+)오류 발생

VoucherRepository를 구현하는 구현체 둘
JdbcVoucherRepository와 MemoryVoucherRepository



둘이 @Profile에 매칭이 되어야 bean으로 등록이 된다.
@Profile 중 하나는 active하게 만들어줘야 한다.
이를 위해서는 테스트 시 테스트 클래스의 최상단에 @AvtiveProfiles()를 이용해
active하게 만들어줄 Profile을 전달한다.

만일 test환경이 아니라 JDBC 환경까지 생각한다면 Profile로 "dev"를 전달해줄 수도 있을 것이다.

설명
테스트 실행 시 @SpringJUnitConfig으로 test Context frameWork가 만들어지고 거기에서
applicationContext를 만들어준다. @Configuration에 의해 applicationContext가 만들어지고 @ComponentScan으로 각각의 서비스와 레포지토리를 빈에 등록한다.
이 때 @ActiveProfiles("test")을 적용시켜서 test Profiles에 관련된 빈들이 생성된다.
Profiles을 작성해주지 않은 클래스들도 등록되고(?)
@Profiles을 작성해준 클래스들은 @Repository에 의해 등록이 되지만
@Profiles의 인자로 넣어준 Profiles을 사용하는 경우에만 등록이 된다.

따라서 test @Profiles을 active하게 만들어주었기 때문에 test profiles을 사용하는
MemoryVoucherRepository가 사용되는 것이다.

그래서 실제 Orderservice Bean이 생성되고
필요한 dependency에 있는 객체들도 다 같이 생성되어 의존관계가 형성된다.

이 때는 Mock을 전달한 것이 아니라
실제 Bean으로 등록된 객체 간 상호협력관계를 테스트 한 것이다.

(= 통합테스트)

이것이 스프링에서 제공해주는 테스트 프레임워크이다.

@SpringBootTest
@SpringBootTest를 통해 테스트하게 되면 SpringBoot 어플리케이션이 실제 구동된다.
SpringBoot 어플리케이션에 대한 통합 테스트 진행 가능.(나중에 학습 예정)

일단은 스프링에서 제공해주는 테스트 프레임 워크 위주로 학습하는 것을 추천한다.

profile
개발 공부를 해라

0개의 댓글