본문으로 건너뛰기

Rails에서 Minitest::Spec 사용 시 주의해야 할 라이프사이클 훅의 함정

Using Minitest::Spec in Rails? Watch out for the lifecycle hooks!

작성자
발행일
2026년 03월 03일
https://remimercier.com/minitest-spec-and-rails-hooks/

핵심 요약

  • 1 Rails 환경에서 Minitest::Spec의 before 블록과 Rails 고유의 setup 블록을 혼용하면 실행 순서의 차이로 인해 예기치 않은 테스트 실패가 발생할 수 있습니다.
  • 2 Rails는 ActiveSupport::TestCase를 통해 setup 블록을 Minitest의 before_setup 훅에 삽입하므로, 일반적인 setup 메서드나 before 블록보다 항상 먼저 실행됩니다.
  • 3 테스트 코드의 가독성과 안정성을 유지하기 위해서는 한 가지 설정 방식(Syntax)을 표준으로 정하고 일관되게 사용하는 것이 기술적 부채를 줄이는 핵심입니다.

도입

이 글은 Ruby on Rails 환경에서 Minitest::Spec을 사용할 때 발생할 수 있는 테스트 라이프사이클 훅의 충돌 문제를 다룹니다. 저자인 Remi Mercier는 프로젝트 진행 중 before 블록과 setup 블록을 혼용했을 때 발생하는 NoMethodError와 같은 비직관적인 오류의 원인을 분석합니다. Rails가 Minitest의 내부 훅을 어떻게 확장하는지 이해함으로써, 개발자가 테스트 스위트의 신뢰성을 높이고 디버깅 시간을 단축할 수 있는 실질적인 통찰을 제공하고자 합니다.

1. 문제의 발단: 혼용된 테스트 문법

Rails 프로젝트에서 Minitest::Spec 스타일을 도입하면 두 가지 설정 문법이 공존하게 되는 경우가 빈번합니다. 개발자마다 선호하는 방식이 다를 수 있기 때문입니다. - before { ... }: Minitest::Spec에서 제공하는 문법으로, RSpec과 유사한 경험을 제공합니다. - setup { ... }: Rails의 ActiveSupport에서 제공하는 고유 문법입니다.

저자는 동일한 테스트 파일 내에서 상위 컨텍스트에는 before를, 중첩된(nested) 컨텍스트에는 setup을 사용했을 때 인스턴스 변수가 nil이 되어 NoMethodError가 발생하는 현상을 발견했습니다. 흥미롭게도 이 두 블록의 위치를 바꾸면 테스트가 정상적으로 통과하는 기이한 현상이 나타났습니다. 이는 단순히 문법의 차이가 아니라 실행 순서의 근본적인 차이에서 기인합니다.

2. Minitest의 기본 라이프사이클 이해

일반적인 Minitest의 실행 순서는 다음과 같이 정의됩니다. 1. before_setup: 라이브러리나 프레임워크 확장을 위해 예약된 빈 훅입니다. 2. setup: 실제 테스트 설정을 수행하는 메서드입니다. Minitest::Specbefore 블록은 내부적으로 이 setup 메서드를 호출하는 문법적 설탕(Syntactic Sugar)에 불과합니다. 3. after_setup: 설정 직후, 테스트 실행 직전에 호출되는 훅입니다. 4. 테스트 케이스 실행: 실제 it 블록이나 test_ 메서드가 실행됩니다.

기본적으로 def setupbefore 블록은 동일한 2단계에서 실행되므로, 순수 Minitest 환경에서는 선언된 순서대로 실행되어 큰 문제가 발생하지 않습니다.

3. Rails의 개입과 실행 순서의 역전

문제는 Rails가 Minitest를 통합하는 방식에 있습니다. Rails는 ActiveSupport::TestCaseActiveSupport::Testing::SetupAndTeardown 모듈을 prepend하여 동작 방식을 확장합니다.

여기서 핵심적인 차이가 발생합니다. Rails의 setup 블록은 Minitest의 setup 메서드가 아니라, 그보다 앞선 단계인 before_setup 훅에 등록됩니다. 이로 인해 다음과 같은 실행 계층이 형성됩니다.

  • 1단계 (before_setup): Rails의 setup 블록들이 파일 내 위치와 상관없이 가장 먼저 실행됩니다.
  • 2단계 (setup 메서드): Minitest의 표준 def setup 또는 Minitest::Specbefore 블록이 실행됩니다.

결과적으로 코드 상에서 beforesetup보다 위에 작성되어 있더라도, 실제 런타임에서는 Rails의 setup 블록이 무조건 먼저 실행됩니다. 만약 setup 블록이 before 블록에서 초기화할 예정인 인스턴스 변수에 의존하고 있다면, 해당 변수는 아직 nil 상태이므로 오류가 발생하게 되는 것입니다.

4. 해결책 및 권장 사항

이러한 혼란을 방지하고 테스트 스위트의 안정성을 확보하기 위해서는 다음과 같은 실천 방안이 권장됩니다.

  • 표준화 (Picking a Standard): 프로젝트 내에서 setup 블록을 쓸지, before 블록을 쓸지 하나만 정해서 일관되게 사용해야 합니다. 혼용은 잠재적인 버그의 온상이 됩니다.
  • 역할 분담: 데이터 생성 및 객체 인스턴스화에는 let을 활용하고, 인증 처리나 외부 API 스터빙(stubbing)과 같은 부수 효과가 필요한 설정에만 before/setup을 사용하는 식으로 역할을 명확히 구분합니다.
  • 프레임워크 이해: Rails가 Minitest를 어떻게 래핑하고 있는지 이해하면, 라이프사이클 관련 오류가 발생했을 때 소스 코드를 추적하여 원인을 빠르게 파악할 수 있습니다.

결론

테스트 프레임워크의 내부 동작 원리를 이해하는 것은 복잡한 버그를 해결하는 데 필수적입니다. Rails가 Minitest를 확장하는 방식 때문에 발생하는 라이프사이클의 미묘한 차이는 개발자에게 큰 혼란을 줄 수 있습니다. 따라서 팀 내에서 명확한 코딩 표준을 수립하고, 도구가 제공하는 마법 뒤의 원리를 파악함으로써 더 견고하고 예측 가능한 테스트 환경을 구축해야 합니다. 도구의 유연함이 때로는 독이 될 수 있음을 인지하는 것이 중요합니다.

댓글0

댓글 작성

댓글 삭제 시 비밀번호가 필요합니다.

이미 계정이 있으신가요? 로그인 후 댓글을 작성하세요.

0/1000
정중하고 건설적인 댓글을 작성해 주세요.