프론트엔드 테스트의 필요성
테스트를 함으로써 이점이 무엇이 있을까?
- 버그 감지
- 코드 품질 향상
- 리팩토링 안정성 보장
- 기능 검증
- 사용자 신뢰 제공
- 자동화와 통합
등등 이유는 많을 것이다.
요약하지면 코드 안정성과 신뢰성을 보장하기 위해 테스트를 하는것은 좋은 방법 중 하나이다.
과거에는 상대적으로 프론트엔드가 크게 복잡하지 않아 테스트를 잘 도입하지 않았다고 한다.
하지만 점차 프론트엔드의 비중이 높아지고, 중요해지면서 프론트엔드의 테스트 또한 주목받고 있다.
클린 코드
에서도 테스트와 관련하여 재미있는 설명이 있었는데,기존의 코드가 모두 올바르게 동작하는지 확인하는 마법의 버튼이 있다면 코드가 제대로 작동하는지 확인하기 위해 버튼을 누를것이고 결국 코드를 한 줄 작성할 때 마다 그 버튼을 누를 것 이라는 내용이었다.
이런 마법의 버튼이 있다면 정말 도움이 되지 않을까?
여기서 “마법의 버튼”을 만드려면 우리는 모든 기능이 제대로 작동하는지 확인하는 테스트 코드를 작성해야한다.
프론트엔드도 예외는 아닐 것이다.
테스트 종류
- 유닛 테스트 - 블록과 코드 단위의 개별 테스트. 리액트에서는 함수나 훅 또는 컴포넌트 단위
- 컴포넌트 테스트 - 리액트 컴포넌트에 더 초점을 맞춘 테스트. 랜더링, 상호작용 및 동작을 테스트 함.
- 통합 테스트 - 여러 요소에 대한 테스트. 함수와 훅, 컴포넌트를 함께 테스트 함.
- E2E 테스트 - 사용자 시나리오를 실제 브라우저 환경에서 테스트 함.
- 스냅샷 테스트 - 랜더링 출력을 저장하여 테스트 시 컴포넌트의 랜더링 출력과 비교함.
Next.js 테스트 라이브러리
공식문서에서 소개하는 테스팅 라이브러리는
- Vitest (유닛 테스트)
- Jest (유닛 테스트, 스냅샷 테스트)
- Playwright (E2E 테스트)
- Cypress (E2E 테스트, 컴포넌트 테스트)
로 총 4개가 있다.
async 컴포넌트는 아직 테스트 라이브러리에서 유닛 테스트를 대부분 지원하지 않기 때문에 E2E 테스트로 테스트하기를 권장한다.
필자는 E2E 테스트와 컴포넌트 테스트가 둘 다 가능한 Cypress가 매력적으로 보였다
자세한 설치 과정은 공식문서를 참고한다
Cypress 컴포넌트 테스트
컴포넌트 테스트는 전체 애플리케이션을 빌드하지 않고도 특정 컴포넌트를 테스트할 수 있다.
아래와 같이 구현해야하는 버튼 컴포넌트가 있다.
버튼 컴포넌트는 가져야 할 여러 옵션 및 효과가 있다.
- 색상 (기본, 다크, 라이트)
- 반응
- 비활성화
- 로딩
- 크기 Large, Medium, Small (이미지 상으로는 실제와 크기가 약간 상이함)
테스트 코드 작성하기
위 여러 옵션과 효과를 바탕으로 테스트해야할 사항을 정리하면 아래와 같다.
- 색상 옵션에 따른 변화
- 버튼 클릭시 변화
- 비활성화 옵션에 따른 변화
- 로딩상태 옵션에 따른 변화
- 크기 옵션에 따른 변화
아래는 테스트 코드 중 일부이다. 크기 옵션에 따른 변화를 테스트하기 위한 코드를 아래와 같이 작성해보았다.
describe('BoxButton Component', () => { it('renders correctly with different sizes', () => { mount( <BoxButton buttonType='rect' size='l' theme='default'> Large Button </BoxButton>, ) cy.get('button').should('contain', 'Large Button').and('have.class', 'py-[16px]') mount( <BoxButton buttonType='rect' size='m' theme='default'> Medium Button </BoxButton>, ) cy.get('button').should('contain', 'Medium Button').and('have.class', 'py-[14px]') mount( <BoxButton buttonType='rect' size='s' theme='default'> Small Button </BoxButton>, ) cy.get('button').should('contain', 'Small Button').and('have.class', 'py-[8px]') }) })
컴포넌트 테스트도 결국에는 컴포넌트가 해당 스타일을 가지고 있는지 코드상으로 확인해야하기에
.and('have.class')
메소드를 통해 크기에 따른 tailwindcss 스타일 클래스가 변화하는지 확인하는 방식이다.모든 테스트를 작성한 뒤 실제 브라우저 환경에서 테스트가 진행되는 모습이다.
컴포넌트 테스트 후기
사용 전에는 굳이 컴포넌트 단위의 테스트가 필요할까? 라는 생각이 들었었다.
하지만 컴포넌트의 동작을 실제로 검증하면서 생각이 바뀌었다. 컴포넌트 테스트를 통해 개발 초기 단계에서부터 오류를 발견하고, 그에 따라 신속하게 수정할 수 있었다.
단순히 UI가 올바르게 렌더링되는지 검증하는 것을 넘어서, 컴포넌트의 각 기능과 상호작용이 예상대로 동작하는지까지 확인할 수 있었다. 예를 들어, 버튼 컴포넌트의 경우 클릭 이벤트가 정상적으로 발생하는지, 상태 변화에 따른 스타일 변경이 제대로 적용되는지 등을 체크할 수 있다.
이전보다 코드의 수정에 두려움을 느끼지 않을 수 있고 시간이 지난 후에 컴포넌트의 수정이 필요해도 테스트 코드에 의지하며 리펙토링을 진행할 수 있을것 같다.