be 단위 테스트

데브코스

목록 보기
123/131

백엔드 단위 테스트, 한 번에 이해하기

코드 짜고 "될 것 같은데?" 하고 배포했다가 실제로 터진 경험, 한 번쯤 있을 거다. 단위 테스트는 그 "될 것 같은데?"를 "된다"로 바꿔주는 안전망이다. 핵심부터 한 줄로 정리하면 이렇다.

단위 테스트(Unit Test) = 코드의 가장 작은 단위(함수·메서드)가 의도대로 동작하는지 자동으로 검증하는 것


쉽게 비유하면

자동차 조립 공장의 부품 검사라고 생각하면 됨! 자동차(서비스) 다 조립하고 나서 "잘 달리나?" 테스트하면 문제 찾기가 너무 늦다. 그래서 엔진 하나, 브레이크 하나, 핸들 하나씩 조립 전에 부품 단위로 먼저 검사한다.

  • 부품 검사(단위 테스트) → 각 함수가 제대로 동작하나
  • 조립 검사(통합 테스트) → 여러 부품이 붙었을 때도 되나
  • 실주행 테스트(E2E 테스트) → 실제 유저처럼 써봤을 때도 되나

단위 테스트는 이 중 제일 작고 빠른 첫 번째 관문 같음. 부품이 이미 불량이면 조립해봤자 의미 없으니까!


자세히

테스트의 종류 (피라미드)

         /\
        /E2E\         ← 느리고 비용 큼, 적게
       /------\
      /  통합   \      ← 중간
     /----------\
    /  단위 테스트 \   ← 빠르고 가볍고, 많이
   /--------------\

아래로 갈수록 빠르고 가볍다. 단위 테스트를 제일 많이 짜고, E2E는 핵심 흐름만 골라서 짜는 게 이상적인 비율 같음.

단위 테스트 (Unit Test)

함수·메서드 하나씩 검증. 이 글의 주인공. DB나 외부 API 안 쓰고, Mock으로 대체해서 빠르게 돌린다.

통합 테스트 (Integration Test)

여러 모듈이 붙었을 때 잘 동작하는지 검증. 예를 들어 "API 엔드포인트 → 서비스 로직 → 실제 DB까지" 한 번에 흘려보는 거다. 단위 테스트보다 느리지만, "각 부품은 멀쩡한데 조립하니까 안 된다"를 잡아줌.

E2E 테스트 (End-to-End Test)

E2E는 End-to-End, 즉 "끝에서 끝까지"라는 뜻이다. 실제 유저가 브라우저에서 하는 행동 전체 흐름을 처음부터 끝까지 자동으로 돌려보는 테스트다.

  • 예: "로그인 → 상품 검색 → 장바구니 담기 → 결제 완료" 이 흐름 전체를 코드가 브라우저 켜서 직접 클릭하면서 검증
  • 실제 브라우저를 돌리기 때문에 제일 현실과 가깝지만, 그만큼 느리고 환경에 민감해서 가끔 이유 없이 깨지기도 함 (이걸 flaky test라고 함)
  • 도구: Playwright, Selenium, Cypress 등

비유하면 단위 테스트는 부품 검사, 통합 테스트는 조립 후 검사, E2E는 실제 도로에서 시운전하는 거 같음!

좋은 단위 테스트의 조건

  • 빠름 — 수백 개 돌려도 몇 초면 끝나야 함
  • 독립적 — 다른 테스트에 영향 안 받아야 함. DB·외부 API 같은 것 안 씀
  • 반복 가능 — 언제 돌려도 같은 결과가 나와야 함
  • 명확함 — 뭘 테스트하는지 읽으면 바로 알아야 함

핵심 개념

Given / When / Then 패턴

테스트를 세 단계로 구성하는 방식. 거의 모든 테스트가 이 구조를 따름.

Given: 이런 상황에서 (준비)
When:  이걸 했을 때 (실행)
Then:  이래야 한다 (검증)

모킹(Mocking)

단위 테스트는 DB나 외부 API를 실제로 안 쓴다. 대신 "가짜 객체(Mock)"로 대체해서 "DB가 이 데이터를 돌려줬다고 치고" 테스트한다. 덕분에 DB 없이도 빠르게 테스트 가능 같음.

커버리지(Coverage)

전체 코드 중 테스트가 실행하는 코드 비율. 100% 커버리지가 목표처럼 느껴지지만, 실무에선 80% 안팎을 현실적인 목표로 잡는 경우가 많음. 숫자보다 중요한 로직에 테스트가 있냐가 더 중요 같음!

백엔드 언어별 대표 테스트 도구

언어테스트 프레임워크
JavaScript / TypeScriptJest, Vitest
Pythonpytest, unittest
JavaJUnit
Gotesting (내장)

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 이상이어야 합니다")
  })
})

이렇게 짜두면 나중에 포인트 로직 바꿀 때, 테스트 돌려서 빨간불 뜨면 "어 뭔가 깨졌다"를 즉시 알 수 있음.

실무 시나리오

  • 배포 전 CI/CD 파이프라인에서 테스트 자동 실행 → 테스트 깨지면 배포 막힘
  • 리팩토링할 때 기존 동작 보장 → "구조는 바꿨는데 결과는 같다"를 테스트가 증명해줌
  • 버그 고칠 때 먼저 버그를 재현하는 테스트 짜고 → 고친 후 테스트 통과 확인 (이걸 "버그를 테스트로 가두기"라고 함)

한 방 정리

구분내용
한 줄 정의함수 하나하나가 의도대로 동작하는지 자동 검증
비유자동차 부품 단위 검사
핵심 패턴Given / When / Then
DB·외부 API는?Mock으로 대체해서 빠르게
JS/TS 대표 도구Jest, Vitest
테스트 3계층단위(부품 검사) → 통합(조립 검사) → E2E(시운전)
E2E 대표 도구Playwright, Selenium, Cypress

쉽게 외우면 "함수 하나 짜면, 테스트 하나 짜는 습관" — 처음엔 귀찮아 보여도 나중에 리팩토링·배포할 때 진짜 빛나는 게 단위 테스트 같음!

profile
Dive Head First | Work Super Hard | Attract Great People

0개의 댓글