[Frontend] 테스트 코드의 조건
들어가며
프론트엔드 개발에서 테스트는 버그를 줄이고, 리팩토링을 쉽게 만들어주는 중요한 수단입니다. 그렇다면 어떤 코드가 테스트하기 쉬운 코드일까요? 이 글에서는 테스트 용이성을 높이기 위한 조건들과 함께, 관련 예시 코드도 함께 살펴보겠습니다.
목차
- 순수 함수 사용하기
- 단일 책임 원칙 지키기
- 예측 가능한 코드 작성하기
- 테스트를 위한 코드 수정, 괜찮을까?
- 결론
1. 순수 함수 사용하기
순수 함수란 다음과 같은 특징을 가진 함수입니다:
- 동일한 입력에 대해 항상 동일한 출력
- 외부 상태나 환경에 의존하지 않음
- 부수 효과(side-effect)가 없음
이런 함수는 독립적으로 테스트가 가능해 매우 이상적인 테스트 대상입니다.
✅ 순수 함수 예시
1
2
3
4
// 입력만 받아 출력만 반환하는 순수 함수
export function add(a: number, b: number): number {
return a + b;
}
❌ 비순수 함수 예시
1
2
3
4
let counter = 0;
export function increment() {
counter += 1;
}
위 함수는 외부 상태(counter)에 의존하고 이를 변경하므로 테스트하기 어렵습니다.
2. 단일 책임 원칙 지키기 (SRP)
하나의 함수/모듈은 하나의 책임만 가져야 테스트가 쉽습니다. 여러 기능을 동시에 수행하는 함수는 테스트하기 어렵고, 실패했을 때 원인 파악도 어렵습니다.
❌ 좋지 않은 예시
1
2
3
4
5
6
// 데이터 요청 + 렌더링을 한 함수에서 수행
async function fetchAndRenderUser() {
const res = await fetch('/api/user');
const user = await res.json();
document.getElementById('username')!.textContent = user.name;
}
이 함수는 데이터 요청과 DOM 조작이라는 두 가지 책임을 가지므로 테스트가 까다롭습니다.
✅ 개선된 예시
1
2
3
4
5
6
7
8
9
// 역할 분리
export async function fetchUser() {
const res = await fetch('/api/user');
return await res.json();
}
export function renderUserName(name: string) {
document.getElementById('username')!.textContent = name;
}
이제 각각의 함수는 독립적으로 테스트 가능해집니다.
3. 예측 가능한 코드 작성하기
예측하기 쉬운 코드는 테스트하기도 쉽습니다. 이를 위해 다음을 지켜주세요:
- 명확한 변수명과 함수명
- 일관된 로직 흐름
- 상태 변경이 명확히 드러나는 구조
❌ 예측 어려운 코드
1
2
3
function process(d: any) {
return modify(update(d));
}
✅ 예측 가능한 코드
1
2
3
4
function updateUserData(user: User): User {
const updatedUser = { ...user, active: true };
return updatedUser;
}
함수명과 변수명이 명확하므로 이해하기 쉽고, 테스트할 때 어떤 동작이 일어날지 쉽게 예측할 수 있습니다.
4. 테스트를 위한 코드 수정, 괜찮을까? 🤔
테스트를 위해 다음과 같은 과도한 수정은 지양해야 합니다:
- private 메서드를 억지로 public으로 변경
- 테스트만을 위한 코드 삽입
하지만, 테스트하기 어렵다는 것은 곧 코드에 구조적 문제가 있을 가능성도 있다는 뜻입니다. 예를 들어 다음과 같은 상황입니다:
- 하나의 함수가 너무 많은 역할을 수행
- 외부 의존성이 강하게 결합되어 있음
이럴 때는 테스트 용이성을 높이기 위해 리팩토링을 고려하는 것이 바람직합니다. 이는 단순히 테스트를 위한 변경이 아니라 전체적인 코드 품질 향상으로 이어질 수 있습니다.
5. 결론
조건 | 설명 |
---|---|
✅ 순수 함수 사용 | 입력 → 출력의 흐름이 명확하고 예측 가능 |
✅ 단일 책임 | 테스트 단위가 작고 명확 |
✅ 예측 가능 | 읽기 쉽고 이해하기 쉬운 코드 |
⚠️ 테스트를 위한 무리한 구조 변경은 지양 | 하지만 테스트가 어렵다면 리팩토링을 고려해야 함 |
테스트하기 쉬운 코드는 결국 유지보수가 쉬운 코드입니다. 테스트 코드를 잘 작성하는 것도 중요하지만, 그보다 테스트하기 좋은 구조를 먼저 만드는 습관이 중요합니다.
참고 자료
- [Clean Code - Robert C. Martin]
- [Testing JavaScript - Kent C. Dodds]
- React Testing Library 공식 문서