일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 생각정리
- 자바스터디
- 이펙티브자바
- springboot
- 파라미터 그룹
- 예외
- try-with-reources
- error
- Final
- java
- RDS
- 피리티어
- Unchecked Exception
- AWS
- 바이트코드
- Effective Java
- spring-security
- Checked Exception
- bytecode
- Annotation
- 이펙티브 자바
- Spring
- exception
- https
- 자바
- ec2
- JVM
- 보안 그룹
- Today
- Total
개발 일지
이번 글에서는 테스트 환경을 통합하여 테스트 시간을 단축하는 내용을 작성해 보려고 합니다.
흔히 통합 테스트 코드를 작성할 때 각 테스트 클래스마다 `@SpringBootTest` 어노테이션을 사용합니다.
그러나 이런 방식은 각 테스트 클래스가 독립적으로 애플리케이션 컨텍스트를 생성하게 되어 테스트 실행 시마다 서버를 다시 시작하고 컨텍스트를 로딩해야 합니다. 이로 인해 테스트 실행 시간이 길어지고 리소스가 낭비되는 문제가 발생할 수 있습니다.
해결 방안
@SpringBootTest의 남용을 피하는 방법은 간단합니다. 각 테스트 클래스마다 @SpringBootTest를 사용하는 대신,
@SpringBootTest 어노테이션을 붙인 추상 클래스(abstract)를 생성하고 다른 클래스에서 이를 상속받아 애플리케이션 컨텍스트의 재사용하게 만드는 것입니다.
- @SpringBootTest 어노테이션을 붙인 추상 클래스를 만들기
- 이를 다른 테스트 클래스에서 상속받아 사용하기
- 테스트 환경을 통합하여 애플리케이션 컨텍스트의 재사용을 극대화
적용하기
1. @SpringBootTest 어노테이션을 붙인 abstract 클래스를 작성합니다.
- 공통으로 사용하는 bean이나 설정이 있다면 같이 작성합니다.
IntegrationTestSupport.java
@ActiveProfiles("test")
@SpringBootTest
public abstract class IntegrationTestSupport {
// 공통 설정 및 Bean 정의
@MockBean
protected MailSendClient mailSendClient;
}
2. @SpringBootTest 어노테이션 대신 IntegrationTestSupport 클래스를 상속받게 합니다.
OrderServiceTest.java (@SpringBootTest)
@SpringBootTest
class OrderServiceTest {
}
OrderServiceTest.java (extend IntegrationTestSupport class)
class OrderServiceTest extends IntegrationTestSupport {
}
이렇게 작성하면 간단하게 @SpringBootTest 어노테이션이 붙은 테스트의 환경을 통합할 수 있습니다.
여기서 끝이 아니라 한가지 더 해주어야 하는데 컨트롤러 테스트의 경우 mocking을 사용해서 @SpringBootTest 가 아닌 `@WebMvcTest` 어노테이션을 사용했습니다. @WebMvcTest 또한 각각의 Spring Boot 애플리케이션 컨텍스트를 생성하기 때문에 @WebMvcTest을 붙인 컨트롤러용 abstract 클래스를 따로 작성해 주어야 합니다. 구조는 위와 같음으로 코드만 적어 두겠습니다.
ControllerTestSupport.java
@WebMvcTest(controllers = {
OrderController.class,
ProductController.class
})
public abstract class ControllerTestSupport {
@Autowired
protected MockMvc mockMvc;
@Autowired
protected ObjectMapper objectMapper;
@MockBean
protected OrderService orderService;
@MockBean
protected ProductService productService;
}
OrderControllerTest.java
class OrderControllerTest extends ControllerTestSupport {
}
결과 확인하기
테스트 환경을 통합하여 abstract 클래스를 상속받는 구조로 변경 완료했습니다. 이제 실행시간이 얼마나 차이가 있는지 확인해 보겠습니다.
before
- Springboot 서버가 7번 띄워졌고 4.519초
after
- Springboot 서버가 2번 띄워졌고 3.162초
테스트 코드가 44개 뿐인 작은 프로젝트임에도 불구하고 유의미한 시간 단축을 확인할 수 있었습니다.
정리
각각의 테스트 클래스에 @SpringBootTest, @WebMvcTest를 사용하면 테스트마다 독립적인 Spring Boot 애플리케이션 컨텍스트가 생성됩니다. 이는 테스트하는 데 걸리는 시간을 증가시키고 시간은 비용이기 때문에 결과적으로 비용을 증가시킵니다. 이를 막기 위하여 추상클래스에 어노테이션을 사용하고 각 클래스에서 이를 상속받는 방법으로 테스트 환경을 통합을 시켰고 작은 토이 프로젝트임에도 불구하고 유의미한 시간 단축의 결과를 확인할 수 있었습니다.
앞으로 규모가 큰 프로젝트를 경험하게 될 때에도 이러한 리소스들을 어떻게 관리하는지가 중요할 거 같아서 남용되고 있는 자원이 어떠한 것들이 있는지 관심 있게 살펴보아야겠습니다. 또한 @SpringBootTest, @WebMvcTest 들이 애플리케이션 컨텍스트를 생성하는 과정에 대해서도 정리해 보려고 합니다.