Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions 05장/조혜린.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
## 5장. 자동 테스트: 좋은 소프트웨어를 만드는 최고의 습관

### 1. 자동 테스트의 이점

자동 테스트는 기존 코드의 동작을 검증하고, 변경으로 인해 발생할 수 있는 회귀 버그를 발견하는 데 도움을 줌. 또한 테스트를 작성하는 과정에서 코드의 책임과 의존 관계를 파악하게 되므로 유지보수성 향상에도 기여함. 충분한 테스트가 갖춰져 있다면 기존 코드를 수정하거나 리팩터링할 때 변경에 대한 자신감을 높일 수 있음.

자동 테스트는 동일한 조건에서 반복적으로 실행할 수 있어 코드 변경 이후에도 기존 동작이 유지되는지 지속적으로 검증할 수 있음. 수동으로 반복해서 테스트하는 데 필요한 시간과 노력을 줄이고, 개발 과정에서 빠른 피드백을 제공함.

책 전반에 걸쳐 테스트의 중요성이 계속 반복해서 등장한다. 처음에는 테스트를 단순히 기능이 정상적으로 동작하는지 검증하는 수단으로 생각했다면, 책을 읽으면서 테스트가 유지보수성과 개발자의 자신감에도 영향을 미친다는 점을 느낀다.
특히 기존 코드를 수정할 때 테스트가 있다면 변경으로 인한 영향을 조금 더 확신을 가지고 검증할 수 있다는 점에서 테스트를 잘 사용해봐야겠다는 생각이 들었다.

## 2. 자동 테스트 유형

### 단위 테스트, 통합 테스트, 종단 간 테스트

- **단위 테스트:** 개별 함수나 구성요소의 동작을 독립적으로 검증. 실행 속도가 빠르고 문제 발생 위치를 파악하기 쉬움.
- **통합 테스트:** 여러 구성요소가 연결되었을 때 올바르게 상호작용하는지 검증.
- **종단 간 테스트(E2E):** 실제 사용자 관점에서 애플리케이션의 전체 흐름이 정상적으로 동작하는지 검증.

각 테스트는 검증 범위와 실행 비용이 다르므로 프로젝트의 특성과 요구사항에 맞게 적절한 비중을 결정해야 함.

개인적으로는 세 가지 테스트 중 단위 테스트가 가장 중요하지 않을까 생각한다. 개별 기능이 충분히 검증되어 있다면 통합 테스트나 E2E 테스트에서 문제가 발생하더라도 원인을 파악하고 해결하기가 상대적으로 수월할 것 같기 때문이다. 상위 단계에서 발견되는 문제 중 일부도 결국 개별 기능에 대한 검증이 충분하지 않아 발생하는 것은 아닐까 싶다.

물론 단위 테스트만으로 모든 문제를 발견할 수는 없겠지만, 작은 단위의 동작이 확실하게 검증되어 있어야 그 위에 쌓이는 기능들도 안정적으로 동작할 수 있다고 생각한다. 그렇기에 단위 테스트를 얼마나 충실하게 작성하는지가 전체 테스트의 신뢰성에도 큰 영향을 미칠 것 같다.

### 테스트하지 말아야 할 것

작성한 코드의 모든 부분을 동일한 수준으로 테스트할 필요는 없음. 외부 라이브러리나 프레임워크가 이미 보장하는 동작을 중복해서 테스트하기보다 직접 작성한 코드의 동작에 집중해야 함. 또한 내부 구현 세부사항보다는 외부에서 관찰할 수 있는 동작을 검증하는 것이 바람직함.

단순히 테스트 수를 늘리기보다 실제로 의미 있는 동작을 검증하는 테스트를 작성하는 것이 중요함.

## 3. 코드 실행률

코드 실행률(Code Coverage)은 전체 코드 중 테스트 과정에서 실행된 코드의 비율을 측정하는 지표. 실행률이 높다고 테스트의 품질이 반드시 높은 것은 아니며, 코드가 실행되었다는 사실만으로 올바른 동작이 검증되었다고 볼 수 없음.

100% 실행률 달성 자체를 목표로 삼기보다 핵심 로직과 위험 요소를 충분히 검증하고 있는지 확인하는 것이 중요함.

이 부분을 읽으면서 **코드 실행률은 목적이 아니라 수단이 되어야 한다**는 점을 다시 한번 생각하게 되었다. 결국 테스트의 목적은 높은 수치를 달성하는 것이 아니라 코드가 의도한 대로 동작하는지 검증하는 데 있기 때문이다.

실행률이라는 수치에만 집중하다 보면 정작 중요한 검증이 이루어지고 있는지는 놓칠 수도 있을 것 같다. 앞으로도 어떤 지표를 활용하든 그 수치 자체를 높이는 것보다 지표를 통해 무엇을 확인하고 개선하려는 것인지 먼저 생각해야겠다고 느꼈다.

## 4. 테스트 작성

### 테스트 우선 개발과 테스트 후 작성

- **테스트 우선 개발(TDD):** 구현 전에 실패하는 테스트를 작성하고, 테스트를 통과하는 코드를 구현한 뒤 리팩터링하는 방식.
- **테스트 후 작성:** 기능을 먼저 구현한 다음 동작을 검증하는 테스트를 추가하는 방식.

두 방식 모두 코드의 동작을 검증한다는 목적을 가지며, 개발 상황과 요구사항에 따라 적절한 방식을 선택할 수 있음.

테스트를 먼저 만들어놓고, 이후에 구현하는 형식인 테스트 우선 개발(TDD)에 대해서 딱히 생각해본적 없는데 이 방법도 시도해보면 좋을 것 같다는 생각이 들었다. 물론 이 방법이 무조건적으로 좋다고 장담할 순 없지만 테스트를 먼저 만들어놓는다면 내가 구현하는 기능에 대해 계속해서 올바른지 확인하며 구현할 수 있을 것 같아서 한 번 꼭 해봐야겠다는 생각이 든다.

### 모의 객체와 외부 의존성 분리

모의 객체(Mock Object)는 실제 의존 구성요소 대신 사용되는 객체로, 테스트 대상의 동작을 외부 의존성으로부터 분리해 검증할 수 있도록 함. 외부 서비스의 응답을 제어하거나 구성요소 간 상호작용을 검증하는 데 활용할 수 있음.

개인적으로는 MSW나 Mock을 활용해 테스트하는 방식이 더 효율적이라고 생각한다. 실제 API나 DB에 의존하는 테스트를 작성했다가 외부 환경에 문제가 발생하면, 테스트 대상 코드에는 문제가 없더라도 테스트가 실패할 수 있기 때문이다. 이런 문제를 해결하는 데 불필요한 리소스가 발생할 수 있다는 점에서 외부 의존성을 분리하는 방식이 더 합리적으로 느껴진다.

다만 실제 API나 DB와의 연결에서 발생하는 문제까지 검증하려면 별도의 통합 테스트가 필요하다는 점도 고려해야 할 것 같다. 결국 모든 테스트에서 실제 구성요소를 사용하는 것보다는 검증하려는 목적에 따라 Mock과 실제 구성요소를 적절히 선택하는 것이 중요하다고 생각한다.

### 통합 테스트와 종단 간 테스트 작성

통합 테스트는 여러 구성요소를 함께 실행해 실제 연결 관계와 상호작용을 검증함. 종단 간 테스트는 HTTP 요청부터 응답과 데이터 처리까지 실제 사용자 흐름에 가까운 방식으로 검증함.

단위 테스트만으로 확인하기 어려운 구성요소 간 문제를 발견할 수 있지만, 일반적으로 더 많은 실행 시간과 환경 구성이 필요함.
Loading