Frontend Unit Test 작성하기

해당 본문은 Things to Consider when Frontend Unit Testing 글 기반으로 개인적인 생각을 더하여 작성하였다.

왜 Frontend에서 단위 테스트 작성을 더 어렵게 느낄까?

기존에 단위 테스트를 작성하지 않던 개발자에게 단위 테스트 작성을 전파하다 보면 백엔드보다 프론트엔드에서 테스트 작성을 더 어려워하는 느낌이다. 물론 그 원인은 개발자의 테스트에 대한 숙련도, 개발 능력, 프로젝트 상황 등 다양한 원인들에 의해서 달라질 수 있기 때문에 한정지어서 말할 순 없다.

하지만 공통적으로 테스트 대상을 보면, 테스트하기 어렵게 만들어져 있는 경우가 많다. 컴포넌트 분리나 책임에 따른 모듈 분리 등은 고려하지 않고, 퍼블리싱된 html과 css를 들고와서 이벤트 처리와 api를 통한 데이터를 처리하는 기능만 채우는 등의 개발 패턴이 테스트하기 어렵게 만든다.

  • stub을 통해 테스트 상황을 만들기 위해서, 소스 코드 분석에 많은 시간이 든다.
  • 모듈 또는 컴포넌트 분리가 없는 경우가 많기 때문에 mocking하기 어려워 테스트 작성이 어렵다.
  • 검증 대상이 많아서 테스트 코드는 길어지고, 가독성이 떨어지며 유지보수 하기가 어렵다.

단위 테스트에서 검증할 항목

역할에 따른 모듈 분리를 어디까지 하느냐에 따라 달리질 수 있지만, Component, Page를 대상으로 단위 테스트에서 검증 항목을 분리하면 다음과 같다.

Component

Atomic Design 관점에서 atom(원자), molecule(분자), organism(유기체)에 해당되는 컴포넌트

  • render 시점에 prop 값을 사용하여 컴포넌트가 어떻게 그려지는지 Presentation 영역 처리
    • 예. prop 값이 보여지거나, 자식 컴포넌트에 prop 전달 등
  • 이벤트 처리
    • 예. 부모 컴포넌트로 이벤트를 전파

Page

  • render 시점에 Presentation 영역 처리
  • 이벤트 처리
    • 예. 컴포넌트와 동일하게 단순 이벤트를 처리하거나, api를 호출하여 데이터 변경 작업 수행
  • 프론트엔드 비지니스 로직 처리
  • 라이프 싸이클 관련 처리

테스트 대상(SUT, System Under Test)에 따라서 검증할 항목이 달라진다. 하지만 테스트 대상에 따라 테스트를 통해서 커버할 범위를 정해놓으면 테스트 작성이 쉬워진다.

반복을 통해서 숙련도가 쌓이면 테스트 작성에 드는 시간이 줄어들고, 이는 테스트 작성을 하면 시간이 오래 걸리거나, 생산성이 줄어든다는 내용으로 테스트 작성을 반대하는 불만을 잠재울 수 있다. 물론 그러기 위해서 가장 중요한 것은 테스트 대상을 작게 만들고, 테스트하기 쉽게 만드는 리팩토링 과정이 반드시 필요하다.

Atomic Design

단위 테스트를 쉽게 만드는 방법

어떻게 하면 단위 테스트를 좀 더 쉽게 진행할 수 있는지 알아보자.

“Testable한 코드를 작성하라.”

단위 테스트를 쉽게 작성하기 위해서는 테스트 대상이 Testable(테스트가 가능)해야 한다. Testable한 소스코드 작성을 통해서 유지보수하기 좋은 코드 품질을 얻을 수 있다.

Testable한 소스를 작성한다는 것은?

  • 컴포넌트를 역할에 따라 분리한다.
  • Presentation 기능 (이벤트 처리, 렌더링을 포함한 시각화)과 UI의 비지니스 로직을 분리한다.
  • 반복되는 기능의 경우 모듈을 분리한다.

단위 테스트 파일

  • 보통 *.spec.js 또는 *.test.js 파일의 이름을 가진다.
  • describe 함수를 사용하여, 테스트 검증 항목별로 그룹 분리를 통해서 가독성 높이고, 테스트 작성을 쉽게 만들 수 있다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 테스트 파일

    describe('render', () => { //데이터 로딩과 시각화

    });

    describe('event', () => { //이벤트 처리와 presentation 로직

    });

    describe('method', () => { //비지니스 로직

    });

    describe('lifecycle', () => { //프론트엔드 프레임워크 lifecycle 관련

    });

Unit Test를 지속하는 방법

테스트 작성이 어느 정도 익숙해지면 패턴이 생긴다. 유사한 케이스들이 차곡 차곡 쌓이면, 테스트가 점점 쉬워진다.

개발 초기에는 새로운 유형의 테스트 상황이 발생하면서 테스트 작성에 많은 시간이 들지만, 어느 정도 시간이 쌓이면 기법적인 부분들은 확보되기 때문에 쉽게 작성할 수 있다.
오히려 팀에서 쌓이는 테스트 노하우를 개발 팀원들과 어떻게 공유하고 확산할 수 있을지 방법을 고민하는 것이 중요해진다.

그럼에도 불구하고 개발자들이 ‘개발해야 하는 기능은 많은데 테스트를 작성하면 시간이 오래 걸려서, 시간이 부족하다.’라고 생각한다면..

  • 내부 Onboarding 교육을 통해서 테스트 작성 방법에 대한 이해를 높이고, 테스트에 익숙하게 하라.
  • 테스트 대상(SUT)를 테스트하기 쉽도록 개발하고, 그렇지 않은 경우 리팩토링을 수행한다.

이런 노력을 통해서 팀에 단위 테스트 작성을 정착하고, 지속할 수 있다.

마무리

초반에 테스트가 부족한 경우, 다양한 테스트 유형이 확보되기 전까지 시간과 노력이 들 수 있다. 하지만 그 과정을 지나고 나면 단위 테스트는 생산성을 떨어트리지 않는다.

화면에 기능이 변경되면 테스트는 당연히 실패한다. 개발 과정 중에 버그를 초기에 발견할 수 있기 때문에 더 적은 비용으로 문제를 해결할 수 있다. 당연하지만, 운영 환경에 배포하고 나중에 장애를 발견하여 조치하는 것보다 훨씬 덜 Risky하다.

결론적으로 단위 테스트는 기능 변경에 따른 안전 장치기 때문에 시스템의 유지보수성을 높이고, Testable한 코드 작성을 통해서 유지보수하기 좋은 코드 품질을 얻을 수 있다.

Unit Test의 생산성과 품질

참고

Share