DRAMA&COMPANY
We're Hiring!
No Result
View All Result
DRAMA&COMPANY
We're Hiring!
No Result
View All Result
DRAMA&COMPANY
No Result
View All Result

병렬테스트로 Rspec 테스트 속도 줄이기

승준 사 by 승준 사
2021년 10월 25일
in Tech
Reading Time: 5 mins read
0

테스트코드를 작성할 필요가 있나요??

입사 이후 테스트 코드를 무조건 작성해야 한다는 말을 듣고 리더에게 했던 질문입니다.
테스트 코드 작성 경험이 없던 저는 기능 개발할 시간도 부족한데 테스트 코드를 작성하는 것은 비효율적이라는 일이라고 생각했습니다.
그러다 보니 처음에는 테스트 범위를 제대로 파악하지 못하거나 단순히 통과만 하게 하는 테스트 코드를 작성했습니다.
지금은 테스트 코드의 이점을 많이 체감하고 있습니다.
특히 배포 후 발견하지 못한 사이드 이펙트가 있을까 걱정하던 저에게 좀 더 자신감이 붙었고 버그 양도 줄어들었습니다.

늘어만 가는 테스트 코드와 시간

프로젝트에 기능이 추가될수록 테스트 코드는 늘어나며 테스트 코드를 실행하는 속도 또한 비례해서 증가합니다.
테스트 코드를 실행하는 시간이 길어질수록 개발자의 생산성은 저하됩니다.
리멤버에는 만 개가 넘는 테스트 코드가 있다 보니 테스트 코드 실행이 오래 걸리는 프로젝트는 한 시간이 넘게 걸리기도 합니다.
이 시간을 줄이기 위해 병렬적으로 테스트를 실행하는 방법을 적용해보게 되었습니다.

병렬 테스트

리멤버의 많은 서버 프로젝트는 Ruby on Rails로 개발되고 있고 이를 위한 테스트 프레임워크는 RSpec을 사용하고 있습니다.

Ruby on Rails 6부터는 병렬 테스트 기능이 공식적으로 포함되었으나 아쉽게도 RSpec과 다른 테스트 프레임워크인 MiniTest에 대해서만 그 기능을 지원하고 있습니다.
따라서 RSpec을 사용하는 저희는 이 기능을 이용할 수 없었고 대체재를 찾던 중 RSpec, UnitTest 등 다양한 테스트 프레임워크를 지원하는
병렬 테스트 라이브러리 “parallel_tests”(링크)를 찾게 되었습니다.

참고: 이 글을 쓰는 시점에서는 Ruby on Rails에서 RSpec에 대한 병렬 테스트 기능을 지원하지 않지만 추후에는 지원이 가능할지도 모릅니다. 관련된 내용은 GitHub 이슈(링크)가 생성되어있으니 참고하시길 바랍니다.

parallel_tests

최근 대부분 컴퓨터는 여러 대의 CPU 코어를 갖고 있지만 RSpec은 기본적으로 하나의 CPU 코어만 사용합니다.
병렬 테스트는 여러 CPU 코어를 활용하여 테스트 코드를 그룹으로 나눠 동시에 실행합니다.

앞서 말씀드린 것처럼 parallel_tests는 여러 테스트 프레임워크를 지원하지만, 이 글에서는 RSpec을 기준으로 작성하고 있습니다.

설치

gem 'parallel_tests', group: [:test]

데이터베이스 설정

테스트 코드는 각자 데이터 침범 없이 독립적으로 실행되어야 하므로 parallel_tests는 각 테스트 그룹에 대해
테스트를 실행하는 프로세스별로 독립된 데이터베이스를 사용합니다.
각 프로세스에서 데이터베이스를 사용하기 위해 다음과 같이 config/database.yml 파일의
test environment에 TEST_ENV_NUMBER 환경 변수를 데이터베이스 이름 뒤에 추가합니다.

테스트 프로세스당 한 개의 데이터베이스를 사용하도록 설정하였으니 이제 데이터베이스를 생성해야 합니다.
아래의 명령어는 DB를 생성 후 스키마 로드까지 해줍니다.
기본적으로 사용 할 수 있는 CPU 코어를 사용하지만 직접 개수를 정의 할 수도 있습니다.

rake parallel:setup 
rake parallel:setup[4] 

명령어를 실행했을 때 아래와 같이 DB가 생성된 걸 확인할 수 있습니다.

이제 테스트를 돌리기 전 모든 준비는 완료가 되었습니다.
실제로 병렬테스트를 돌렸을 때 평균적으로 30초 정도 줄어든 걸 확인했습니다.

참고: 테스트 프로세스 수를 무조건 많이 늘린다고 해서 속도가 비례해서 빨라지는 것은 아닙니다. 저의 경우에는 4대로 돌렸을 때 가장 빨랐으며 그 이상으로 늘렸을 때 오히려 효율이 높지 않았습니다.

(병렬 테스트를 돌리기 전)

(병렬 테스트를 돌린 후)

테스트 그룹 균형있게 분할하기

테스트 그룹은 균형이 맞지 않게 분할이 될 수 있습니다.
오래 걸리는 테스트가 많이 포함된 그룹이 있을 때 다른 그룹들은 가장 느린 그룹을 기다리게 하여 전체적인
테스트 완료 시간을 늦춥니다.
아래 명령어를 사용하여 테스트 그룹의 균형을 균일하게 유지합니다.
.rspec_parallel 파일에 다음과 같은 코드를 추가합니다.

--format progress
--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log

(테스트별 런타임 그룹)

각 테스트 파일에 대한 런타임 통계를 지정된 로그 파일에 저장합니다.
다음 실행에는 테스트를 보다 균형 잡힌 그룹으로 나누는 데 사용됩니다.
parallel_runtime_rspec.log 파일이 생성되기 전 첫 번째 실행일 경우에는 시간이 더 걸릴 수 있습니다.
이 로그 파일은 테스트 실행 시 로드되며 각 프로세스가 거의 같은 시간에 완료되도록 테스트가 그룹화됩니다.

캐시 문제 해결하기

한 개의 캐시 저장소만 있는 경우 다른 테스트 프로세스에서 캐시를 동시에 참조하면 캐시 관련 테스트가 쉽게 실패할 수 있습니다.
이 문제를 해결하기 위해서는 프로세스마다 독자적인 캐시 저장소가 있어야 합니다.
저의 경우에는 프로세스별로 file_store 캐시 저장소를 사용하는 방법으로 해결하였습니다.

config.cache_store = :file_store, Rails.root.join("tmp", "cache", "parallel_tests#{ENV['TEST_ENV_NUMBER']}"

이 외에도 cache_store로 Redis를 쓰는 경우에 프로세스별로 Redis channel를 나눠서 해결하는 방법 등 여러 가지 방법이 있으니 상황에 적합한 해결 방법을 찾아보시면 좋을 것 같습니다.

로거

Rspec::Summarylogger

프로세스별 테스트 출력을 기록합니다.
—-format progress 명령어는 테스트 성공 여부를 점 형태로 나타냅니다.

--format progress
--format ParallelTests::RSpec::SummaryLogger --out tmp/spec_summary.log

Rspec::FailuresLogger

실패한 예제에 대해서 볼 수 있는 로그를 생성합니다.

--format progress
--format ParallelTests::RSpec::FailuresLogger --out tmp/failing_specs.log

마무리

병렬테스트를 도입하는 데에 어려운 부분이 없고 테스트 코드의 실행 속도가 많이 개선되기 때문에
도입할 가치가 충분히 있다고 생각합니다.
Test::Unit, RSpec, Cucumber, Spinach을 사용하시는 분들은 한번 사용해보시면 좋을 것 같습니다.

참고

  • https://github.com/grosser/parallel_tests
  • https://steemit.com/rails/@davidalphen/rails-5-2-parallel-tests-with-rspec-for-local-and-travis
  • https://oozou.com/blog/running-specs-in-parallel-before-rails-6-84
  • https://rubynor.com/blog/2020/03/rails-rspec-elasticsearch-parallel-test-suite/

이 글 공유하기:

  • 트위터로 공유하기 (새 창에서 열림)
  • 페이스북에 공유하려면 클릭하세요. (새 창에서 열림)

관련

Tags: Railsruby병렬 테스트테스트 코드

Related Posts

리멤버는 서비스 모니터링을 어떻게 하고 있을까?
Tech

리멤버는 서비스 모니터링을 어떻게 하고 있을까?

안녕하세요? 리멤버를 서비스하고 있는 드라마앤컴퍼니의 플랫폼 서버 파트 테크리드 이한별 ⭐ 입니다. 😂 리멤버는 명함 관리부터 시작하여 인재 검색(다이렉트 소싱), 채용 공고, 헤드헌팅을 비롯한 채용 사업 뿐 아니라 주요 경제 소식을 매일 큐레이션 및 정리해주는 리멤버 나우, 회원들끼리 직장 관련...

2022년 6월 21일
리멤버 서버/웹 팀은 어떻게 일을 하는가?
Tech

리멤버 서버/웹 팀은 어떻게 일을 하는가?

이번 글에서는 리멤버 서비스들의 웹 사이트와 API, 인프라를 담당하고 있는 서버/웹 팀이 일하는 모든 방식을 다루고 있습니다. 추상적인 글을 넘어서 실제 스크릿샷 등을 포함하여 저희가 어떻게 일을 하고 있는지 낱낱이 보여 드리고자 합니다.

2020년 12월 21일
[인터뷰] “6개월 전의 코드가 부끄럽고 아쉬웠어요.”
Tech

[인터뷰] “6개월 전의 코드가 부끄럽고 아쉬웠어요.”

‘성장’을 갈망하는 4년차 개발자 인터뷰Server/Web팀 강태화님, 이민구님이 리멤버를 선택한 이유.   강태화님 : 4년차 개발자이자 리멤버 서버 개발자. ‘세상을 변화시키는 작은 조직’에 동참하고 싶다는 그는 사진앱을 개발하다, IoT 회사의 펌웨어 개발자를 거쳐 리멤버 서버 개발자로 합류 이민구님 : 4년차 프론트...

2020년 11월 30일
Next Post
CODE GURU REVIEWER를 사용하여 코드리뷰 받기

CODE GURU REVIEWER를 사용하여 코드리뷰 받기

리멤버에서 Pull Request 편리하게 사용하는 법

리멤버에서 Pull Request 편리하게 사용하는 법

답글 남기기 응답 취소

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

DRAMA&COMPANY

© 2021 DRAMA&COMPANY

Sites

    Follow Us

    No Result
    View All Result
       

      댓글 로드중...