테스트 코드
애플리케이션이 요구 사항에 맞게 동작하는지 검증하는 행위
테스트 코드를 작성해야 하는 이유
기능 명세서를 봤을 때 이 기능 명세서대로 어떻게 작동하는지 알 수 있다. 수동으로도 가능하지만 기능 명세서가 많아지면 시간이 오래 걸리게 되는데, 이때 테스트 코드가 있다면 빠르고 짧게 자동으로 검증할 수 있고 인간의 실수를 바로잡을 수 있어 코드의 두려움이 자신감으로 바뀔 수 있다.
테스트 예시
테스트의 자동화 과정
장점
- 사람이 수행해야 하는 반복된 테스트를 자동화할 수 있음 ( 비용 감소 )
- 사람이 수행하는 것보다 훨씬 빠르게 테스트할 수 있음
- 사람이 수행하는 것보다 더 신뢰할 수 있음
단점
- 감각적인 요소 ( 시, 청각 ) 등 사용자 경험과 관련된 문제를 찾아낼 수 없음
- 실제 환경에서 벌어지는 다양한 상황을 자동화하기 어려움 ( 네티워크, 디바이스 관련 등)
테스트 자동화를 누가 하는가?
개발자가 테스트를 작성하는 이유
- 코드 품질을 위해서 계속해서 리팩토링 등의 개선 작업 필요
- 이 과정에서 기존에 잘 동작하던 프로그래밍을 망칠 수 있기 때문에 적극적으로 코드를 개선하지 않게 됨
- 따라서 신뢰할 수 있는 자동화된 테스트가 있다면 적극적으로 코드를 개선할 수 있음
테스트의 종류 ( 범위에 따라 )
1. 단위 테스트
- 모듈(함수, 클래스) 단위의 테스트
- 작성 비용이 적게 들고 실행 속도가 빠름
- 작은 단위이기 때문에 실패했을 때 문제가 생긴 부분을 비교적 정확하게 파악할 수 있음
- ex) 계산기에서 덧셈 함수, 메서드가 진행됐을 때 올바르게 나오는지 테스트
2. 통합 테스트
- 단위 테스트보단 큰 범위
- 개별 모듈(함수, 클래스)들이 연결되어 제대로 상호작용하는지 테스트
- 단위 테스트에 비해 실패 시 문제가 생긴 부분을 정확히 파악하기가 어려움
3. E2E 테스트
- 실제 사용자가 사용하는 것과 같은 조건에서 전체 시스템 테스트
- 단위/통합 테스트에 비해 작성이 어렵고 실행 속도가 비교적 느림
- API 서버, DB 등의 외부 서비스들을 모두 사용하여 통합된 시스템을 테스트
좋은 테스트란?
- 실행 속도가 빨라야 한다.
- 빠른 피드백은 개발 속도를 향상시켜준다.
- 너무 느리면 테스트를 자주 실행하지 않게 된다.
- 때문에 속도가 다른 단위/통합/E2E 테스트를 잘 배분해서 테스트한다.
- 내부 구현 변경 시 실패하지 않아야 한다.
- 리팩토링할 때 테스트가 깨진다면 오히려 코드 개선을 방해한다.
- 자주 변하는 로직과 변하지 않는 로직을 구분한다.
- 기능 들에 따라 우선순위를 둔다. 자주 변하는 로직은 다른 기능들에 변동 사항은 없는지, 영향을 없는지 먼저 체크한다.
- 버그를 검출할 수 있어야 한다.
- 소스 코드에 버그가 있어도 검출하지 못하면 잘못된 테스트다.
- 테스트가 기대하는 결과를 구체적으로 명시하지 않으면 버그를 검출할 수 없다.
- 테스트에 결과가 안정적이어야 한다.
- 특정 환경에서만 실패하거나, 실행할 때마다 결과가 달라지는 테스트는 신뢰할 수 없음
- 외부 환경의 영향을 최소화해서 동일한 결과를 최대한 보장할 수 있는 게 중요함.
- 의도가 명확히 드러나야 한다.
- 가독성: 기계가 읽기 좋은 코드가 아닌 사람이 읽기 좋은 코드로
- 테스트 코드를 보고 한눈에 어떤 내용을 테스트하는지를 파악할 수 있어야 한다.
테스트 ROI ( 투자 수익률 )
테스트 코드 작성과 유지 보수는 비용이다.
- 불필요한 테스트나 잘못 짜인 테스트는 차라리 없애자.
비용 대비 효과가 충분한가?
- 테스트를 작성하는 비용에 비해 얻을 수 있는 효과가 더 큰 것인지 고려한다.
- 로직이 거의 없는 코드는 따로 하지 않는다. ex) 이벤트 페이지, 단순 입출력 페이지
- 테스트 범위에 대해 조절한다. ( 단위 vs 통합 vs E2E )
커버리지 100% 목표로 하는 것은 비효율적
커버리지: 코드들이 테스트로 얼마나 커버되었는지 확인하는 지표
- 커버리지가 높아질수록 ROI는 원만해진다. 적절한 선을 찾는 것이 중요하다.