작업 일지#8 테스트 개선 -1-
개요
그동안, 프로젝트를 진행하면서, 테스트는 그저 서비스 로직이 스프링 컨테이너 안에서 제대로 작동하고 있는지를 확인하는 수단으로 생각했다. 물론, 테스트 코드가 많으면 많을수록, 서비스 로직의 안정성을 보장하는 안전장치가 더 탄탄해진다는 뜻이기도 하니, 작업자의 심신을 안정시키는 데에는 큰 기여를 해준다고 볼 수 있다. 하지만 한가지 문제가 발생했다. 바로 빌드시간이 증가하고 있다는 것이다. 이번 게시글에서는 이 빌드 시간이 증가하고 있는 원인을 찾고, 개선하는 과정을 정리하고자 한다.
INDEX
- 현상 파악
- 원인 파악
- 테스트의 종류와 툴의 종류
현상파악
우선 가장 먼저해야할 내가 인식한 문제가 정말로 발생하고 있는 문제인지를 검증해야한다. 검증하는 방법들 중 가장 간단한 방법으로는 빌드 기록을 살펴보는 것이다. 아래 이미지를 한번 보자.
현재 진행하고 있는 프로젝트의 빌드 관리는 깃헙 액션을 통해서 이루어지고 있다. 젠킨스와는 달리 따로 CI 서버를 구축할 필요없고, yml문서로 api를 호출하여 사용하는 편의성을 이점으로 채택하여 사용하고 있다. 또한 프로젝트 관리를 깃헙으로 하고 있기 때문에, 빌드 결과를 좀 더 직관적으로 살펴볼 수 있다는 점을 장점으로 채택하였다. 이야기가 잠시 옆으로 셌는데, 위 이미지에 나와있는 시간을 보자. 분명 초기에는 30-40초 였는데, 작업을 진행하고 코드가 많아질수록, 빌드의 평균시간이 조금씩 증가하더니, 거의 2배 가까이 증가하고 있는 것을 알 수 있다. 아직 모든 도메인의 로직이 완료되지 않은 시점에서도 상황이 이렇다면, 나중에, 로직이 증가되고 애플리케이션이 증가한다면, 나중에는 빌드를 하는 것만으로도 많은 시간을 잡아먹을 것이다. 다음의 두 이미지를 보자
위의 이미지들은 프로젝트를 빌드를 하는 데, 필요한 github action의 워크플로우의 job에 따라, 걸리는 시간을 단계적으로 기록이 되어있는 것이다. github action에 대한 내용은 따로 문서를 작성하여 설명하도록 하겠다. Maven의 명령어에 대해 설명하자면, verify
는 Maven의 프로젝트를 빌드하기 전에, validate
를 통해 프로젝트 구조를 검증하고, compile
을 통해 코드를 컴파일하며, package
를 통해 jar
를 빌드한다. 이 과정에서, 프로젝트에 작성된 테스트코드를 작동시키는데, 만약 테스트를 통해 잘못된 로직이 발견된다면, Maven은 로그 메세지로 오류를 알리고 빌드를 멈춘다. clean
의 경우, 기존에 빌드된 jar
패키지를 지우는 명령어인데, 리팩토링 과정에서 기존에 빌드된 jar
와 패키지가 불일치하여 생기는 오류를 방지하기 위해 추가하였다.
원인파악
본론으로 들어가서, 이미지 안의 job의 소요시간을 비교해보면, 아래의 경우, clean
단계가 추가되어 빌드 통합 시간이 늘어난 것도 있지만, 기존의 verify
단계의 job 처리 시간이 3배 가까이 증가한 것을 알 수 있다. 원인을 파악하기 위해선, 앞에서 언급한 verify
가 처리하는 영역을 살펴보면 될 것 같은데, 그 과정을 통하여 다음과 같이 내용을 정리해볼 수 있다.
- 빌드과정에서 컴파일해야할 코드의 수가 많아졌다.
- 테스트 완료시간이 증가하였다.
1.
의 경우는 필연적이지만, 항상 관찰하고 개선해야할 부분일 수 있다. 특히 리팩토링을 할 경우, 기존에 작성한 코드를 그대로 빈으로 등록해두고, 방치하거나, Maven, Gradle에 사용하지 않는 dependency
들을 그대로 방치 한다면, 빌드시간이 증가할 확률이 커질 것이다. 특히 spring-boot-starter-***
와 같은 dependency
의 경우, 개발자의 편의를 위해 자동으로 등록해주는 빈이 많은 데, 이렇게 자동으로 등록해준 빈들을 사용하지 않는다면, 분명 나중에는 리소스 낭비로 이어질 수도 있다. 그러나, 이 부분은 아직 한참 프로젝트의 기본 기능을 넣는 과정에서는 조금 시기상조일 수 있다. 학습을 병행하며, 기능을 추가하는 상황이라, 여러가지 시행착오가 있는 상황이라, '불필요한 코드'가 발생하는 것은 결과적으로는 어쩔 수 없는 상황이며, 이 부분에 대한 개선 작업은 모니터링 툴을 활용하여, 좀더 꼼꼼하게 분석하고, 개선하는 것이 더 효과적일 수 있기 때문이다. 따라서, 현재 시점에서는 이 부분으로 인해 빌드 시간이 길어질 수 있다는 점만 인지하고, 우선은 보류하는 것이 바람직할 것 같다.
그렇다면, 좀더 적극적으로 개선을 해볼 수 있는 부분은 2.
의 테스트 코드일 듯 하다. 가장 극단적이고 간단한 방법은 테스트 코드를 없애버리는 것인데, 테스트 코드를 통해 기존 코드에 오류가 없음을 검증하여, 개발자의 심신을 안정시키고, 이전 작업을 검토할 시간과 리소스를 줄여, 다음 작업에 가속도를 붙이면서, 유지보수성을 늘리는 이점이 있다는 점을 고려한다면, 삭제하여서, 빌드 시간을 줄인다는 것은, 트레이드 오프의 편자가 너무 심하다. 그렇다면, 어떻게 개선을 해볼 수 있을까? 먼저 테스트의 종류와 SpringBoot를 통해 진행할 수 있는 테스트 툴의 종류를 살펴보자
테스트의 종류와 툴의 종류
크게 3가지가 있다고 본다. 단위 테스트(Unit Test)와 통합 테스트(Integration Test), 그리고 인수 테스트(Acceptance Test)가 있다.
단위 테스트(Unit Test)
애플리케이션에서 테스트 가능한 가장 작은 소프트웨어를 실행하여 기능이 예상대로 동작하는지 확인하는 테스트이다. Java에서는 주로 JUnit을 활용한다.
통합 테스트(Integration Test)
단위 테스트 보다는 좀더 큰 단위로 진행하는 테스트로, 여러 모듈을 모아서 이들이 의도대로 협력을 하는지 확인하는 테스트이다. SpringBoot 환경에서 개발을 한다면 다음과 같이 @SpringBootTest
애노테이션을 가지고 통합 테스트를 수행할 수 있다. 여기서 @SpringBootTest
애노테이션을 활용하여, 테스트 환경에서 애플리케이션 컨텍스트를 형성하는 Bean
들을 로드한다.
인수 테스트(Acceptance Test)
사용자의 스토리에 맞춰 수행하는 테스트이다. 위의 두 가지의 테스트들과 다르게 비즈니스 쪽에 초점을 둔다. 인수 테스트는 애자일 개발 방법론 중 하나인 익스트림 프로그래밍(XP)에서 사용하는 용어이다. 시나리오에 맞게 정상 작동하는지의 여부를 확인하는 테스트로, 통합 테스트와는 비슷하지만, 엄연히 다른 종류의 테스트이다. 이 테스트에서 요구하는 것은 '누가, 어떤 목적으로, 무엇을 하는가' 이다.
인수 테스트는 소프트웨어 내부 코드에 관심을 갖기보다는 실제 사용자 관점에서 테스트하는 경우가 많다. 이러한 종류의 테스트를 블랙박스 테스트라고도 부른다. Java에서는 대표적으로 MockMvc
와 같은 도구를 활용하여 인수 테스트를 작성할 수 있다.
마무리
이번 일지에서는 프로젝트의 기능이 많아짐에 따라 빌드시간이 길어지는 상황에서 그 원인을 파악하여, 기존 테스트 코드를 개선하는 쪽으로 방향을 잡았다. 그리고, 테스트의 종류과 Java에서 수행할 수 있는 테스트 툴을 정말 간단하게 알아보았다. 다음 일지에서는 기존 테스트 코드의 구조를 살펴보고, 그 구조에서 문제를 발견하고, 개선을 시도해보는 쪽으로 진행을 해보겠다.