Test란?
테스트란 개발된 코드가 기대한 대로 동작하는지 검증하는 일련의 과정이다.
테스트를 통해 버그를 사전에 방지하고, 코드의 신뢰성과 유지보수성을 높일 수 있다.
테스트에는 유닛 테스트(클래스나 함수의 로직 점검), 통합 테스트(여러 계층 간의 연동 검증),
E2E테스트(사용자 플로우 검증), 성능/부하 테스트 등 다양한 테스트가 있다.
테스트 피라미드
테스트 피라미드는 테스트 전략의 개념으로, 상단으로 갈수록 더 복잡하고 시간이 오래 걸리고,
하단으로 갈수록 더 작고 빠르게 실행되는 테스트를 의미한다.
단위 테스트(Unit Test)
피라미드의 가장 아랫단에 위치하는 단위 테스트란 소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는지
검증하는 절차이고, 하나의 모듈을 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트이다. 여기서 모듈은
하나의 기능 또는 메서드 등이 될 수 있다. 예를 들어 만약 웹 애플리케이션에서 로그인 메서드에 대해 테스트한다면
단위 테스트가 될 수 있다. 단 이때 다른 계층은 Mock으로 처리하여 메서드의 로직만을 테스트해야 한다.
통합 테스트(Integration Test)
통합테스트는 단위 테스트보다 한 단계 위의 개념으로, 여러 계층 또는 컴포넌트가 실제로 잘 연동되는지를 검증
하는 테스트이다. 따라서 Service, Respository, DB 등 실제 컴포넌트들이 서로 통합되어 잘 작동하는지를
확인한다. 예를 들어 회원가입 기능을 테스트할 때 UserService.save() 메서드 내부 로직만 검증하고
의존성은 Mock으로 대치한다면 유닛테스트이지만, UserService가 UserRepository를 사용하고, DB에
저장되는 것까지 확인하면 통합 테스트라고 할 수 있다.
단위 테스트의 필요성
통합 테스트의 경우 실제 여러 컴포넌트들이 구동된 상태에서 테스트를 해야 하기 때문에 시스템을 구성하는
컴포넌트들이 많아질수록 테스트를 위한 비용(시간)이 매우 커지게 된다. 하지만 단위 테스트의 경우
해당 부분만 독립적으로 테스트하기 때문에 빠르게 검증할 수 있다. 따라서 실무에서 테스트 코드를 작성한다고
하면 대부분은 단위테스트를 의미한다.
1. 버그를 초기에 발견할 수 있다.
단위 테스트는 로직 단위로 오류를 사전에 확인할 수 있기 때문에 리팩토링이나 확장 시
생기는 오류를 빠르게 탐지할 수 있다.
2. 리팩토링 안전성 확보
단위 테스트가 있다면, 구조 변경 후에도 기능이 동일하게 동작하는지 바로 검증이 가능하다.
3. 개발 문서이자 명세의 역할
단위 테스트 자체가 특정 함수의 입력값에 대해 이렇게 동작해야 한다는 명세의 역할을 한다.
다른 개발자가 테스트를 보고 함수의 의도와 사용법을 명확히 이해하는데 도움이 된다.
4. 코드 신뢰성 보장
배포 전 테스트를 실행하여 코드 변경이 기존 기능에 영향이 없는지 확인할 수 있어 코드 신뢰성을
보장할 수 있다.
단위 테스트의 문제점과 stub
단위 테스트는 어떤 메서드나 기능에 대해 독립적으로 테스트를 진행하는 것이기 때문에 만약 해당
메서드나 기능이 다른 객체와 메시지를 주고받는다면 단위테스트를 진행할 수 없다. 따라서 다른 객체
대신 가짜 객체(Mock Object)를 주입하여 어떤 결과를 반환하라고 정해진 답을 준비시켜야 하는데, 이를
stub이라고 한다.
TDD(Test Driven Development)
테스트 주도 개발이란 매우 짧은 개발 사이클을 반복하는 소프트웨어 개발 프로세스 중 하나이다.
먼저 요구사항에 맞는 테스트 케이스를 하나 작성하고 해당 테스트를 통과할 수 있는 최소한의
코드를 작성한다. 테스트가 실패한다면 테스트가 통과될 때까지 코드를 보완하고 테스트가 통과한다면
마지막으로 작성한 코드를 표준에 맞도록 리팩토링 한다. 이 기법을 개발했거나 '재발견' 한 것으로
인정되는 Kent Beck은 TDD가 단순한 설계를 장려하고 자신감을 불어넣어 준다고 한다.
테스트 주도 개발은 테스트 코드를 먼저 작성하고 그에 맞는 코드를 작성하는 개발
방법론이다. 따라서 여기서 테스트란 계층 간의 연결을 검증하는 통합테스트가 아닌
단위테스트이다.
TDD 방법 및 순서
1. 실패하는 하나의 기능을 위한 단위 테스트를 작성한다.
2. 테스트를 빠르게 통과하기 위한 최소한의 코드를 작성한다.
3. 만약 실패한다면 성공할 때까지 코드를 수정한다.
4. 성공한다면 새로운 기능에 대한 테스트 코드를 작성한다.
5. 위의 과정을 반복하며 개발한다.
6. 테스트가 모두 통과되었다면 리팩토링을 하며 코드를 개선한다.
Why TDD?
1. 요구사항을 더 명확하게 파악하고 정의할 수 있다.
테스트는 어떤 입력이 주어졌을 때, 어떤 출력을 기대하는가를 기반으로 작성된다.
따라서 TDD를 하다 보면 개발 전에 이미 요구사항을 논리적으로 정리하게 된다.
2. 불필요한 코드 작성 방지
테스트를 먼저 작성하면 어떤 기능이 필요한지 명확해진다.
그러면 테스트를 통과시키는 최소한의 코드만 작성하면 되므로 불필요한 코드작성을
방지할 수 있다.
3. 리팩토링 안정성 보장
리팩토링 할 때 코드 구조가 바뀌더라도 테스트가 통과되는지의 여부를 통해
코드의 품질을 보장할 수 있으므로 안심하고 리팩토링을 진행할 수 있다.
4. 심리적인 안정감
테스트가 없다면 코드를 바꿔도 되는지 다른 기능들에 영향을 미치는 거 아닌지 등
불안요소가 존재한다. 하지만 테스트가 있다면 변경하고 바로 테스트를 통해 확인할 수 있기
때문에 개발자는 자신감을 가지고 개발을 진행할 수 있다.
참고
https://aws.amazon.com/ko/what-is/unit-testing/
https://www.youtube.com/watch?v=Npi21gLIEZM
https://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%9B_%ED%85%8C%EC%8A%A4%ED%8A%B8
https://mangkyu.tistory.com/143
'Back-end' 카테고리의 다른 글
템플릿 메서드 패턴 알아보기 (0) | 2025.04.03 |
---|---|
데이터베이스를 최적화하는 방법들 (0) | 2025.03.01 |
Redis 알아보기 (0) | 2025.02.27 |