Real Browser Testing 으로 보다 쉽게 프론트엔드 테스트 코드 작성하기

Sungmin Park
IHFB  R&D 팀블로그
7 min readJan 10, 2022
rovenimages.com 님의 사진, 출처: Pexels

프론트엔드 테스트의 특성

복잡한 함수(컴포넌트)를 유닛 테스트 없이 작성한다면 어떨까요? 아마도 매번 기능을 수정할때마다 수동으로 모든 유즈케이스들을 직접 확인해봐야 할 것 입니다.

프론트엔드 테스팅은 개발자가 의도한대로 사용자가 UI와 상호작용을 할 수 있는지 점검합니다. 이러한 자동화된 테스트들로 많은 비용과 에너지를 소모해서 직접 테스팅 하지 않고도 웹사이트가 오류가 없이 릴리즈 될 수 있도록 할 수 있습니다.

하지만 UI 테스팅은 테스트할 대상을 분리시키기 어렵고, 시각적으로 확인할 수 없다는 점 때문에 아직도 많은 개발팀이 테스트 유지보수를 포기하고 종종 위와 같은 방식으로 개발하곤 합니다.

또한 프론트엔드 코드는 단순히 데이터를 가공하는 데서 그치는게 아니라 사용자 이벤트를 다루고 올바른 타이밍에 올바른 View를 보여줘야 하는 특성이 있습니다.

JSDOM 환경 테스트가 쉽지 만은 않은 이유

위와 같은 어려움을 극복하고 UI테스팅 자동화를 도입했다면 아마도 대부분 JSDOM 상에서 운영하고 있을 겁니다. JSDOM 은 실제 브라우저의 DOM 과 비슷한 환경을 구성해주는 훌륭한 Node.js 라이브러리입니다.

JSDOM은 Node.js 환경에서 돌아가기 때문에 속도도 빠르고 대부분의 경우에 꽤 괜찮은 솔루션이지만, 브라우저 표준이 잘 구현되고 테스트되는 것을 해당 라이브러리에 의존해야 하는 점과 브라우저간 동작이 다른 점 등을 포착할 수 없는 단점들을 안고 있습니다. 그리고 또 하나 중요한 점은 … 동작하는 테스트 케이스를 눈으로 확인할 수가 없다는 것입니다!

간단한 Integration 테스트 시나리오를 하나 가정해보겠습니다. 여러분이 어떤 특정한 아이템들의 리스트를 렌더링 해주는 컴포넌트를 테스트 하려는 중이고, 삭제 버튼을 눌렀을 때 리스트중의 아이템 개수가 하나 줄어드는지 테스트 하려고 한다고 하겠습니다.

헌데 삭제하는 버튼을 선택하기 위해서 쿼리를 했는데 도무지 엘리먼트가 찾아지지를 않습니다. 1시간이 넘도록 온갖 추측을 하며 사투를 벌이다가 결국은 테이블의 리스트 자체가 해당 엘리먼트가 비동기적으로 렌더되기 때문에, 렌더를 기다려야함을 깨닫고 엘리먼트가 렌더되기까지 기다리는 코드를 추가합니다.

그렇게 가까스로 assertion 코드를 넣고 통과되는 것을 확인하고 테스트 작성을 마쳤습니다. 근데 나중에 다시 자세히 살펴보니 assertion 부분 코드를 바뀌어도 테스트가 항상 통과합니다. 거짓 양성(false positive)입니다. 삭제를 수행하고 refetch 를 하는 동안 로딩 애니메이션을 보여주는 그때 잠시 리스트 전체가 사라지게 되고, 삭제가 잘 동작한 것처럼 착각을 하게 된 것이죠.

이렇게 긴 시간을 들여서 테스트를 작성했지만 여러분은 매번 이런 소모적인 디버깅 과정을 거칠 때마다 테스트가 생산성을 저하한다는 느낌이 들고 타이트한 일정등의 이유로 테스트를 점점 등한시하게 될 것입니다.

물론 이런 어두운 터널을 지나 경험이 많은 개발자들은 그나마 노련하게 이러한 함정들을 피해서 테스트를 비교적 수월하게 작성할 수 있을 겁니다. 하지만 진짜 문제는 테스트를 이제 막 작성하기 시작하기 시작한 개발자들이 이런 경험을 할 때입니다. UI 테스팅 자체에 회의감을 갖고 그 시간에 다른 실질적인 개발을 하는게 더 생산적이라고 여기게 될 수가 있습니다.

선의를 가지고 시작하게 된 일이 고통스럽고 피곤하기만 한 작업이 된다면, 그것보다 심각한 기술 부채가 또 있을까요?

서론은 이쯤하고 아래부터는 밀당에서 실제 브라우저에서 동작하는 테스팅 환경을 구성하기 위해 새롭게 도입한 테스팅 툴들을 소개해보겠습니다.

실제 브라우저 테스팅 환경 꾸미기

Web Test Runner

Node.js 환경에서 돌아가는 UI 테스팅의 문제점에 착안해서 실제 브라우저에서 테스트를 할 수 있도록 만든 프로젝트가 있습니다.

Running tests in real browsers give greater confidence in (cross-browser) compatibility and makes writing and debugging tests more approachable. -Modern Web Blog

바로 Modern Web 이라는 단체에서 제작한 @web/test-runner패키지 입니다. 기본적으로는 Headless browser 로 테스트를 실행하지만 디버깅 모드에서 실제 브라우저에서 테스트가 실행되는 모습을 볼 수 있습니다. 주의할 점은 테스트 파일의 형식으로 ES Module 만 지원하므로 Common JS 만을 지원하는 라이브러리들이 많이 사용되는 프로젝트의 경우 따로 빌드환경을 세팅해야 하는 경우가 있을 수 있습니다.

uvu

위에서 언급한 ES Module 관련 이유로 저희 팀에서도 Web Test Runner 의 기본 테스트 러너인 Mocha 를 사용할 수가 없어서 대체 테스트 프레임 워크를 찾던 도중 uvu 라는 테스트 프레임워크를 발견했습니다. uvu 는 Node.js 와 브라우저 환경을 모두 지원하는 빠르고 가벼운 테스트 프레임워크입니다.

하지만…

하지만 uvu 가 브라우저 콘솔에만 테스트 결과를 남기도록 되어있어 Web Test Runner와 통신하는데 제한이 있는 문제가 있었습니다. 다행히도 해당 Github 저장소 이슈에 메인테이너가 uvu 를 본따서 만든 커스텀 테스트 프레임워크를 임시로 사용할 수 있도록 남겨놓아서 무리없이 사용할 수 있었습니다.

테스트 전략

밀당에서는 Storybook으로 컴포넌트 카탈로그를 제작하고 있습니다. 여기에는 자주 재사용되는 컴포넌트부터 실제 프로덕트에서 보여지는 것과 동일한 모습의 온전한 스크린까지 포함됩니다.

그리고 각 컴포넌트에서 파생되는 Story 를 테스트의 대상으로 활용하고 있습니다. 아래는 이러한 전략의 몇 가지 장점입니다.

  • 물론 Storybook을 사용하는 팀에게만 해당되겠지만, 스토리와 테스트 케이스 각각 따로 컴포넌트 세팅을 중복으로 할 필요 없이 하나의 스토리로 두 가지 용도를 모두 커버할 수 있습니다.
  • 테스트 케이스가 실패하는 경우 스토리 페이지를 열어서 시각적으로 원인을 파악해 볼 수 있습니다.
  • chromatic 스냅샷 테스트로 의도하지 않은 비쥬얼 변경을 방지할 수 있습니다.

말이 쉽지! 코드를 보여주세요

밀당 프론트엔드에서 실제로 동작하는 코드를 가져왔습니다. 위에서 말씀드린 전략대로 Story 를 우선 구성하고, 해당 Story를 그대로 가져와서 테스트 렌더러에 제공합니다. 리스트에서 아이템 하나를 삭제할 수 있는지 테스트하는 코드입니다. 전체적으로 React Testing Library 의 쿼리 기능으로 엘리먼트를 찾고 몇 가지 유저 액션을 시뮬레이팅 한 후 uvu/assert패키지로 assertion 코드를 넣어서 동작을 확인하는 모습입니다.

그리고 아래는 Web Test Runner 에서 제공하는 Focus 기능으로 특정 테스트 케이스에 접근해서 ‘브라우저로 디버깅하기' 기능을 사용한 모습입니다.

흡사 E2E 테스트를 실행한 모습 같습니다. 이렇게 테스트 코드 작성 중 뭔가 의도한 대로 동작하지 않을때 바로 브라우저를 열어서 무슨일이 벌어지고 있는지 확인할 수 있습니다.

실제 이러한 방식으로 작성한지 두 달 정도 되어가는데, 이전과 가장 다른 점은 더 이상 테스트를 작성하는 것에 대해 거부감이 들지 않는다는 것입니다. 오히려 테스트 코드 작성이 재밌는 일처럼 느껴지고 자신감이 붙습니다. 그때그때 눈으로 문제를 확인하면서 테스트를 작성하니 작성하는데 드는 시간도 확연히 줄어서 부담도 적습니다.

마무리

무엇보다도 가장 중요한 사실은 테스트는 여러분의 발목을 잡는 존재가 아니라 코드의 잠재적 결함을 알려주는 친절한 조수가 되어야 한다는 것입니다. 매번 테스트를 작성하는 일이 복잡한 수학 공식을 푸는 것이 아니라 일상적인 과정을 거치는 것 처럼 느껴져야 합니다. 밀당 FE 팀은 실제 브라우저 환경에서 테스트를 실행하는 것이 이런 목표에 한 발 더 가까워지도록 도와준다고 생각합니다.

밀당 프론트엔드 팀에서 동료를 찾고 있습니다!

밀당 영어가 최근 급성장하여 에듀테크 유니콘이 되기 위해 새로운 시스템을 개발하고 있습니다. 데이터 파이프라인 구축부터 인프라 개선 등 기존 레거시에 존재하는 다양한 문제를 해결, 개선하고 있습니다. 새로운 도전을 즐기시는 분들과 함께 하면 교육의 혁신을 더욱 빠르고 멋지게 이룰 수 있을 것 같습니다!

밀당과 함께할 동료를 찾습니다.

--

--

Sungmin Park
IHFB  R&D 팀블로그

I Hate Flying Bugs에서 프론트엔드 개발을 맡고 있습니다.