- Published on
[React Testing] 시작!
- Authors

jangth
최근에 내가 작성해왔던 코드를 보며 참고하려고 했는데, “어떤 의도로 작성했는지”,” 왜 이렇게 코드를 작성했지?” 라는 생각을 하며 내가 작성한 코드를 욕하기도 하고 반성하게 되었다. 그래서 나는 테스트 코드를 작성하고 학습하면서 더 나은 설계와 코드 문서화를 시작해보려한다.
(학습한 강의) https://www.inflearn.com/course/실무적용-프런트엔드-테스트-1부
테스트란
애플리케이션의 품질과 안정성을 높이기 위해 사전에 결함을 찾아내고 수정하며 기대한 결과대로 동작하는지 검증하는 일련의 행위. 프론트엔드에서는 주로 특정 모듈(특히 컴포넌트)이 잘 동작하는지 테스트로 검증한다. ** 회귀테스트 : 개발자가 직접 테스트 코드를 작성하고 검증하는 테스트
테스트 코드를 작성하려는 이유
- 좋은 설계에 대한 사고를 도와준다.
테스트 코드를 작성하려면 테스트 단위를 나누는 것이 중요한데, 컴포넌트간 결합도가 높다면 테스트 코드를 작성하기 어렵다. (결합도 - 어떤 모듈이 다른 모듈에 의존하는 정도)
따라서 테스트 코드를 작성하기 위해서 결합도는 낮고 응집도는 높은 컴포넌트 단위로 설계하도록 사고를 해야 하는데, 테스트 단위를 어떻게 분리할지 생각하다 보면 좋은 설계 및 사고를 할 수 있도록 도와준다.
- 테스트 코드를 기반으로 안정적으로 리팩토링할 수 있다.
리팩토링은 “결과의 변경 없이 코드의 구조를 재조정함”으로 정의할 수 있는데, 이때 테스트 코드가 있다면 개발자는 사이드이펙트를 방지하면서 빠르고 안정적으로 코드를 리펙토링할 수 있다.
- 애플리케이션의 이해를 돕는 문서가된다.
작성된 테스트 코드가 있으면 어떤 의도로 코드가 작성 되었는지 파악하기 쉽다. 따라서 테스트 코드는 코드 문서화 역할도 한다.
올바른 테스트 코드 작성
- 인터페이스를 기준으로 테스트를 작성
모든 테스트는 세부 구현을 테스트하는 것 대신 서로 다른 클래스 또는 모듈이 상호작용하는 것을 테스트한다. (ex 유저 입장에서 클릭 이벤트가 발생하는지 검증) 내부 구현에 대한 테스트는 강한 의존성 때문에 구현이 조금만 변경되어도 깨지기 쉽고 유지 보수도 매우 어려워진다.
잘못된 테스트 코드
it('isShowModal 상태를 true로 변경했을 때 Component의 display은 block이며, "아녕하세요!" 테스트가 노출된다.', () => {
Component.setState({ isShoModal: true })
})
위와 같이 세부적인 구현 부분까지 테스트를 하게되면,
- 변경되는 상태가 많을 수록 테스트 코드 상에서 일일이 직접 변경해야 하며 어떤 상황에서 변경되는 것인지 알 수 없다.
- 내부 상태값을 검증하기 때문에 설명 자체가 복잡하고 한눈에 알아보기 힘들다.
- 상태 및 변수명이 하나라도 변경된다면 테스트 코드 모두 변경해야 한다. (캡슐화 위반)
올바른 테스트 코드
it('버튼을 클릭하면 모달을 띄운다.', () => {
user.click(screen.getByRole('button'))
})
- 내부 구현과 종속성이 없으며 캡슐화를 위반하지 않는다.
- 한눈에 알아볼 수 있는 설명
- 테스트 커버리지 보다는 의미 있는 테스트인지 고민
커버리지란 테스트 코드가 프로덕션 코드의 몇 %를 검증하고 있는지 나타낸 지표를 말한다. 100% 커버리지를 위해 테스트 코드를 작성하는 것은 유의미한 테스트 코드를 놓치는 문제가 발생하게 된다. 현실적으로 100% 테스트 커버리지로 테스트를 작성하는 것은 불가능하며 테스트 작성, 유지 보수 측면에서 너무많은 비용이 발생하고 100% 커버리지라는 것 자체를 맹신할 수 없다. 따라서 커버리지 수치보단 유의미한 테스트 코드를 작성해야 한다.
- 테스트 코드도 유지 보수의 대상! 가독성을 높이자
- 테스트 하고자 하는 내용을 명확하게 적자
- 하나의 테스트에서는 하나의 동작만 검증하자 (SRP - 단일책임원칙)
- UI 컴포넌트를 사용자가 사용하는 방식으로 테스트
컴포넌트 내부 구현이나 상태에 직접 접근한 것이 아니라 DOM 노드 쿼리(조회)하고 사용자와 비슷한 방식으로 이벤트를 발생시켜 테스트한다.
