테스트 코드 최적화 (feat.Context Caching) #269
jaejae-yoo
started this conversation in
공유
Replies: 1 comment 1 reply
-
|
이전보다 훨씬 깔끔하게 정리해주셨네요..!! |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
관련 PR: #224
저희 팀은 초반부터 테스트 피드백 시간에 대한 고민이 많았었고, @WebMvcTest 활용 등 다양한 방식으로 문제를 해결하려 했었습니다.
하지만 기능 구현이 늘어나면서 테스트 코드 또한 많아지게 되었고, 필연적으로 피드백을 받는 시간이 딜레이됐습니다.
만약 각각의 테스트마다 새로운 스프링 컨텍스트를 띄우면 어떨까요?
매번 새로운 컨텍스트를 띄우기 때문에 테스트를 돌리는 시간이 매우 오래 걸릴 것입니다.
따라서 스프링에서는 Context Caching이라는 것을 제공하는 데요.
따라서 테스트를 매우 빠르게 실행시킬 수 있습니다.
동일한 컨텍스트 구성인지는 어떻게 알 수 있을까요?
ApplicationContext는 로드하는데 사용되는 configuration parameters의 조합으로 고유하게 식별할 수 있습니다. (configuration parameters의 조합을 사용해서 cache key를 생성합니다.)
TestContext 프레임워크는 다음 구성 매개 변수를 사용하여 컨텍스트 cache key를 구성합니다.
locations(from@ContextConfiguration)classes(from@ContextConfiguration)contextInitializerClasses(from@ContextConfiguration)contextCustomizers(fromContextCustomizerFactory) – this includes@DynamicPropertySourcemethods as well as various features from Spring Boot’s testing support such as@MockBeanand@SpyBean.contextLoader(from@ContextConfiguration)parent(from@ContextHierarchy)activeProfiles(from@ActiveProfiles)propertySourceLocations(from@TestPropertySource)propertySourceProperties(from@TestPropertySource)resourceBasePath(from@WebAppConfiguration)여기서 중요한 점은 어떤 bean을 mock으로 했는지(@MockBean)가 컨텍스트 재사용 여부에 영향을 준다는 것입니다(4번째 항목).
따라서 @MockBean 처리한 빈들의 조합이 달라질 경우, 매번 새로운 컨텍스트를 띄우게 됩니다.
프로젝트의 @WebMvcTest에서 매번 새로운 스프링 컨텍스트를 띄우고 있는 이유였습니다.
@WebMvcTest에서는 비교적 가벼운(?) 검증들을 하고 있었는데도 불구하고, 매번 새로운 컨텍스트를 띄우고 있기 때문에, 테스트 효율에 안 좋은 영향을 주고 있었습니다.
예시 코드로 정리해 보았습니다.


BadRequestReviewWebMvcTest클래스와UnauthorizedReviewWebMvcTest클래스는 각각 잘못된 형식으로 요청한 경우(Bad Request)와 사용자 인증과 관련된 예외를 검증하는 @WebMvcTest입니다.두 클래스에서 생성이 필요한 Bean들과 필드에 선언된 MockBean들이
비슷한 듯 조금씩 다른 빈들을 필요로 하고 있다는 것을 알 수 있습니다.따라서 밑의 Run 창을 보시면 둘 다 스프링 컨텍스트를 각각 띄우는 것을 확인해볼 수 있습니다.
그렇다면 여기서 두 클래스가 필요로 하는 Bean들을 통일시키면 어떨까요 ? (물론 사용되지 않는 빈들이 생성되긴 하지만)

UnauthorizedReviewWebMvcTest 클래스가 먼저 실행되었기 때문에 해당 클래스에서는 스프링 컨테이너가 올라갔지만, BadRequestReviewWebMvcTest에서는 스프링 컨테이너가 띄워지지 않은 것을 확인해 볼 수 있었습니다.
즉, 앞에서 생성한 컨테이너를
재사용하고 있다는 것입니다.따라서 @WebMvcTest 환경을 통일하는 방식으로 최적화를 진행해 보았습니다.

WebMVCTest라는 추상 클래스를 만들고 @WebMvcTest 환경에서는 해당 클래스를 상속받도록 했습니다.해당 방식으로 처음 띄워지는 WebMvcTest를 제외하고, 다른 WebMvcTest에서는 새로운 컨텍스트를 띄우지 않고 재사용하는 것을 확인했습니다.
테스트 실행 시간이 엄청나게 줄어들지는 않았지만, 그래도 꽤 줄어들었고 새로운 컨텍스트를 띄우지 않아서 좋은 개선이라고 생각합니다.
References
https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html#testcontext-ctx-management-caching
https://suhwan.dev/2019/03/27/spring-test-context-management-and-caching/
Beta Was this translation helpful? Give feedback.
All reactions