1. 병렬 테스트 환경에서의 고질적인 병목 현상
루비 온 레일즈 환경에서 RSpec을 사용하여 테스트를 수행할 때, 프로젝트 규모가 커지면 테스트 실행 시간도 비례해서 늘어납니다. 이를 해결하기 위해 CI 환경에서 여러 개의 워커(Worker)를 띄워 병렬로 테스트를 실행하는 것이 일반적입니다. 하지만 일반적인 병렬 실행 방식에는 치명적인 약점이 있습니다. 바로 테스트 파일을 최소 단위로 인식하여 워커에 배분한다는 점입니다. 만약 30개의 워커 중 29개가 5분 만에 작업을 끝내더라도, 단 하나의 워커가 35분이 걸리는 거대한 테스트 파일을 할당받는다면 전체 CI 빌드 시간은 결국 40분 이상이 소요됩니다. 이러한 ‘꼬리 지연’ 문제는 개발 팀의 생산성을 크게 저해하며 빠른 배포를 방해하는 주범이 됩니다. 개발자들은 테스트 결과를 기다리느라 컨텍스트 스위칭 비용을 지불하게 되며, 이는 전체적인 개발 속도 저하로 이어집니다.
2. rspec-big-split의 등장 배경과 주요 특징
이러한 문제를 해결하기 위해 고안된 rspec-big-split은 거대한 RSpec 파일을 더 작은 단위로 쪼개어 여러 워커에 분산할 수 있게 해주는 오픈 소스 루비 젬입니다. Knapsack PRO와 같은 파워풀한 유료 도구가 훌륭한 대안이 될 수 있지만, 매달 발생하는 비용 문제나 외부 서비스에 코드를 의존해야 하는 부담, 그리고 데이터 보안 등을 고려해야 하는 기업 환경에서는 rspec-big-split이 매우 강력하고 유연한 커스텀 솔루션이 됩니다. 이 도구는 MIT 라이선스 하에 제공되어 자유롭게 수정 및 배포가 가능하며, 개발자가 어떤 파일을 ‘거대 파일’로 간주하고 쪼갤지 직접 결정할 수 있는 세밀한 제어권을 제공합니다. 또한 별도의 서드파티 서비스 연동 없이 로컬 환경과 CI 환경만으로 동작하므로 신뢰성이 매우 높습니다.
3. 단계별 도입 및 적용 가이드
#### 젬 설치 및 대상 지정 먼저 bundle add rspec-big-split 명령어를 통해 프로젝트에 젬을 추가합니다. 설치 후에는 병목의 원인이 되는 대형 테스트 파일의 RSpec.describe 블록에 ci_split_example_group: true라는 메타데이터를 추가합니다. 이 설정은 해당 그룹이 병렬 실행 시 쪼개질 수 있는 대상임을 명시하며, 작은 파일들은 그대로 유지하여 효율성을 보존합니다.
테스트 맵 생성 및 분석
실제 테스트를 돌리기 전, 프로젝트의 전체 테스트 구조를 파악하는 단계가 필요합니다. RSpec의 dry-run 모드와 제공되는 포매터를 사용하여 테스트 구성 정보를 JSON 파일로 추출합니다. bundle exec rspec –dry-run –format Rspec::Big::Split::Formatter –out tmp/rspec_splitter.json 명령어를 사용하면 됩니다. 이 과정은 실제 테스트를 실행하지 않으므로 매우 빠르게 완료됩니다.
CI 파이프라인 구성
CI 설정 파일에서 전체 노드 수(TEST_NODE_TOTAL)와 현재 노드의 인덱스(TEST_NODE_INDEX)를 환경 변수로 정의해야 합니다. rspec-big-split 명령어는 앞서 생성한 JSON 맵을 읽어 현재 노드가 실행해야 할 최적의 테스트 목록을 계산하여 반환합니다. 이를 RSpec 실행 명령어의 인자로 전달하면 각 워커는 자신에게 할당된 적절한 양의 테스트만 수행하게 됩니다.
4. 극대화된 최적화: 예제 단위 분할 및 기대 효과
기본적인 파일 단위 분할로도 충분하지 않은 경우, –split-by-example 옵션을 활용할 수 있습니다. 이 옵션을 사용하면 파일 내부의 개별 it 블록 단위로 테스트를 쪼개어 워커에 배분하므로, 워커 간의 부하 불균형을 거의 완벽하게 해소할 수 있습니다. 실제 적용 사례에 따르면, 최적화되지 않은 환경에서 450초가 소요되던 테스트가 단 15초로 단축되는 드라마틱한 성능 향상을 기록하기도 했습니다. 이는 개발자에게 즉각적인 피드백을 제공하여 전체적인 소프트웨어 품질 향상에 기여하며, 대규모 모놀리식 테스트 파일로 고통받는 팀에게 가장 현실적이고 비용 효율적인 해결책을 제시합니다.