
코드 짜고 "될 것 같은데?" 하고 배포했다가 실제로 터진 경험, 한 번쯤 있을 거다. 단위 테스트는 그 "될 것 같은데?"를 "된다"로 바꿔주는 안전망이다. 핵심부터 한 줄로 정리하면 이렇다.
단위 테스트(Unit Test) = 코드의 가장 작은 단위(함수·메서드)가 의도대로 동작하는지 자동으로 검증하는 것
자동차 조립 공장의 부품 검사라고 생각하면 됨! 자동차(서비스) 다 조립하고 나서 "잘 달리나?" 테스트하면 문제 찾기가 너무 늦다. 그래서 엔진 하나, 브레이크 하나, 핸들 하나씩 조립 전에 부품 단위로 먼저 검사한다.
단위 테스트는 이 중 제일 작고 빠른 첫 번째 관문 같음. 부품이 이미 불량이면 조립해봤자 의미 없으니까!
/\
/E2E\ ← 느리고 비용 큼, 적게
/------\
/ 통합 \ ← 중간
/----------\
/ 단위 테스트 \ ← 빠르고 가볍고, 많이
/--------------\
아래로 갈수록 빠르고 가볍다. 단위 테스트를 제일 많이 짜고, E2E는 핵심 흐름만 골라서 짜는 게 이상적인 비율 같음.
단위 테스트 (Unit Test)
함수·메서드 하나씩 검증. 이 글의 주인공. DB나 외부 API 안 쓰고, Mock으로 대체해서 빠르게 돌린다.
통합 테스트 (Integration Test)
여러 모듈이 붙었을 때 잘 동작하는지 검증. 예를 들어 "API 엔드포인트 → 서비스 로직 → 실제 DB까지" 한 번에 흘려보는 거다. 단위 테스트보다 느리지만, "각 부품은 멀쩡한데 조립하니까 안 된다"를 잡아줌.
E2E 테스트 (End-to-End Test)
E2E는 End-to-End, 즉 "끝에서 끝까지"라는 뜻이다. 실제 유저가 브라우저에서 하는 행동 전체 흐름을 처음부터 끝까지 자동으로 돌려보는 테스트다.
비유하면 단위 테스트는 부품 검사, 통합 테스트는 조립 후 검사, E2E는 실제 도로에서 시운전하는 거 같음!
Given / When / Then 패턴
테스트를 세 단계로 구성하는 방식. 거의 모든 테스트가 이 구조를 따름.
Given: 이런 상황에서 (준비)
When: 이걸 했을 때 (실행)
Then: 이래야 한다 (검증)
모킹(Mocking)
단위 테스트는 DB나 외부 API를 실제로 안 쓴다. 대신 "가짜 객체(Mock)"로 대체해서 "DB가 이 데이터를 돌려줬다고 치고" 테스트한다. 덕분에 DB 없이도 빠르게 테스트 가능 같음.
커버리지(Coverage)
전체 코드 중 테스트가 실행하는 코드 비율. 100% 커버리지가 목표처럼 느껴지지만, 실무에선 80% 안팎을 현실적인 목표로 잡는 경우가 많음. 숫자보다 중요한 로직에 테스트가 있냐가 더 중요 같음!
| 언어 | 테스트 프레임워크 |
|---|---|
| JavaScript / TypeScript | Jest, Vitest |
| Python | pytest, unittest |
| Java | JUnit |
| Go | testing (내장) |
Node.js 백엔드면 Jest가 사실상 표준 같음.
예시: 유저 포인트 계산 함수 테스트 (Jest + TypeScript)
// calculatePoints.ts
export function calculatePoints(amount: number): number {
if (amount < 0) throw new Error("금액은 0 이상이어야 합니다")
return Math.floor(amount / 1000) * 10
}
// calculatePoints.test.ts
import { calculatePoints } from "./calculatePoints"
describe("calculatePoints", () => {
it("1000원마다 10포인트를 준다", () => {
// Given: 5000원 결제
// When
const result = calculatePoints(5000)
// Then
expect(result).toBe(50)
})
it("1000원 미만은 포인트를 주지 않는다", () => {
expect(calculatePoints(999)).toBe(0)
})
it("음수 금액이면 에러를 던진다", () => {
expect(() => calculatePoints(-1000)).toThrow("금액은 0 이상이어야 합니다")
})
})
이렇게 짜두면 나중에 포인트 로직 바꿀 때, 테스트 돌려서 빨간불 뜨면 "어 뭔가 깨졌다"를 즉시 알 수 있음.
실무 시나리오
| 구분 | 내용 |
|---|---|
| 한 줄 정의 | 함수 하나하나가 의도대로 동작하는지 자동 검증 |
| 비유 | 자동차 부품 단위 검사 |
| 핵심 패턴 | Given / When / Then |
| DB·외부 API는? | Mock으로 대체해서 빠르게 |
| JS/TS 대표 도구 | Jest, Vitest |
| 테스트 3계층 | 단위(부품 검사) → 통합(조립 검사) → E2E(시운전) |
| E2E 대표 도구 | Playwright, Selenium, Cypress |
쉽게 외우면 "함수 하나 짜면, 테스트 하나 짜는 습관" — 처음엔 귀찮아 보여도 나중에 리팩토링·배포할 때 진짜 빛나는 게 단위 테스트 같음!