eelseungmin

[Spring, JUnit5] 테스트 환경 통합으로 비용 절감하기

by eelseungmin

들어가며

기존 프로젝트에 작성한 테스트를 한꺼번에 실행시켰더니 위 사진처럼 내장 톰캣 서버가 8번이나 실행되고 있었다.

 

@DisplayName("PlaceService 통합테스트")
@Sql("classpath:db/teardown.sql")
@ActiveProfiles("test")
@SpringBootTest
class PlaceServiceTest {
	// 생략
}
@DisplayName("ReviewService 통합테스트")
@Sql("classpath:db/teardown.sql")
@SpringBootTest
class ReviewServiceTest {
	// 생략
}

이런 식으로 각 테스트 클래스마다 @SpringBootTest 어노테이션이 달려있을 때 특정 테스트는 test 프로파일이 아닌 다른 프로파일로 동작하도록 되어있는 등, 테스트 환경의 차이가 조금이라도 있으면 서버가 따로 실행된다.

 

서버를 다시 띄우는 것도 결국 자원과 시간을 소모하는 일이고, 프로젝트의 규모가 거대하고 테스트 코드가 수백, 수천 개 이상 작성된 경우라면 이로 인해 낭비되는 시간을 가볍게 볼 수도 없다.

 

나의 경우 테스트 간 환경 차이를 의도하지 않았기에 테스트 환경 통합을 통해 테스트 비용을 절감해보고자 했다.

 

테스트 환경을 통합해보자

Java에서 제공하는 추상클래스를 통해 테스트 환경을 통합하기로 했다.

추상클래스에 구현부를 일부 작성해두고 테스트 클래스들이 이를 상속하도록 하면 되는데, 나는 @SpringBootTest를 통합하기 위한 IntegrationTestSupporter 클래스, @WebMvcTest를 통합하기 위한 ControllerTestSupporter 클래스 2가지를 새로 작성했다.

 

기존에는 Persistence Layer를 테스트하기 위한 @DataJpaTest도 존재했으나 해당 테스트 또한 @SpringBootTest로 통합해서 비용을 더 줄일 수 있다고 생각했다.

@ActiveProfiles("test")
@Sql("classpath:db/teardown.sql")
@SpringBootTest
public abstract class IntegrationTestSupporter {

    @Autowired
    protected JwtProvider jwtProvider;

    @Autowired
    protected EntityManager entityManager;
}
@ActiveProfiles("test")
@WebMvcTest(controllers = {
        UserController.class,
        VoteController.class,
        ReviewController.class,
        PlaceController.class
})
public abstract class ControllerTestSupporter {

    @Autowired
    protected MockMvc mockMvc;

    @Autowired
    protected ObjectMapper objectMapper;

    @MockBean
    protected JwtProvider jwtProvider;

    @MockBean
    protected UserService userService;

    @MockBean
    protected ReviewService reviewService;

    @MockBean
    protected PlaceService placeService;

    @MockBean
    protected VoteService voteService;
}

 

이제 아래와 같이 각 테스트 클래스들이 위에 작성한 클래스들을 상속하도록 하면 된다.

 

통합 전

@DisplayName("ParticipantRepository 단위테스트")
@ActiveProfiles("test")
@DataJpaTest
class ParticipantRepositoryTest {

    @Autowired
    private EntityManager entityManager;
    @Autowired
    private ParticipantRepository participantRepository;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private VoteRepository voteRepository;
    
    // 생략
}

 

통합 후

@DisplayName("ParticipantRepository 단위테스트")
class ParticipantRepositoryTest extends IntegrationTestSupporter {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private VoteRepository voteRepository;

    @Autowired
    private ParticipantRepository participantRepository;
    
    // 생략
 }

추상클래스를 활용한 결과, 테스트 클래스마다 보이던 코드의 반복 또한 줄일 수 있었다.

 

결과

통합 전

- 서버가 8번 실행되고, 테스트 수행 시간은 2.68초가 나왔다.

통합 후

- 서버가 2번 실행되고(@SpringBootTest 환경과 @WebMvcTest 환경 2개), 테스트 수행 시간은 1.88초가 나왔다.

 

수행 시간에서 약 30%의 개선이 이뤄졌음을 확인할 수 있다.

블로그의 정보

eel.log

eelseungmin

활동하기