---
type: knowledge
domain: backend
status: active
last-reviewed: 2026-07-27
---

# 백엔드 테스트 실전

> 한 줄 정의
> 백엔드 결함의 서식지는 로직이 아니라 **경계(DB·외부 API·시간)**다 — 그래서 통합 테스트가 몸통이 된다. 자원 배분·플레이키 일반론은 [[테스트 전략 실전]], 탐색적 테스트·판정은 [[QA 원리]] — 여기는 백엔드 특유의 대역·데이터·주입 규율이다.

## 피라미드 현실판 — 통합이 몸통

| 계층 | 몫 | 대상 |
|------|-----|------|
| 단위 | 도메인 로직·계산·경계값 — 빠르고 많이 | 순수 계층으로 분리된 코드 → [[백엔드 원리]] 도메인 설계 |
| **통합 (몸통)** | **API 호출 → DB까지 관통하는 검증** | 라우팅·검증·트랜잭션·쿼리·직렬화 — 백엔드 결함 대부분이 여기 산다 |
| E2E | 핵심 여정 소수 | 배포 환경 조립 확인용 — 로직 검증을 여기로 올리지 않는다 |

- 백엔드에서 "단위 테스트 수백 개 + 통합 0개"는 초록 불 들어오는 미검증 시스템이다 — 레포지토리를 전부 mock하면 **쿼리가 한 번도 실행되지 않은 채** 커버리지만 오른다.
- 통합 테스트의 단언도 행동 기준이다: 응답 코드·응답 본문·DB의 최종 상태. 내부 호출 순서 검증 금지 → [[테스트 전략 실전]].

## 외부 의존 대역 — 실물 vs 목의 채택 기준

| 의존 | 기본값 | 근거 |
|------|--------|------|
| DB | **실물 (컨테이너·로컬 인스턴스)** | 쿼리·제약·트랜잭션이 검증 대상 그 자체다. 인메모리 대체 DB는 방언 차이로 "테스트만 통과"를 만든다 |
| 외부 API | **목/가짜 서버 (HTTP 레벨)** | 실 서버 호출은 느리고 플레이키하고 부수효과가 있다. 단 **실패 시나리오(타임아웃·5xx·malformed)를 반드시 포함** — 성공 케이스만 목킹하면 어댑터의 존재 이유를 검증 못 한다 → [[외부 연동과 웹훅]] |
| 메일·알림 발송 | 가짜 (기록만 하는 구현) | "보냈다"의 검증은 기록 확인으로 충분, 실발송은 사고다 |
| 큐·스케줄러 | 동기 실행 또는 직접 호출 | 작업 함수를 직접 호출해 검증. 단 cron 표현식의 다음 실행 시각·시간대 계산은 별도로 검증한다 ([[백그라운드 작업과 스케줄링]] cron 검증) |

경계에 어댑터 한 겹이 있으면 대역 교체가 한 곳에서 끝난다 — 대역을 못 끼우는 구조가 곧 설계 결함 신호다.

## 테스트 데이터 규율 — 공유 픽스처 금지

- **모든 테스트가 참조하는 공용 시드 데이터 금지** — 테스트 200개가 "user_1"을 공유하면 데이터 수정 하나가 무관한 테스트 수십 개를 깨뜨리고, 아무도 픽스처를 못 건드리는 동결 상태가 온다.
- 각 테스트가 **자기 데이터를 스스로 만든다** — 반복 셋업은 팩토리/빌더로 감추고, 그 테스트에 의미 있는 값만 명시 → [[테스트 전략 실전]] 테스트 데이터.
- 격리 수단은 테스트별 트랜잭션 롤백 또는 고유 키 — 병렬 실행에서 같은 행을 두 테스트가 만지는 순간 플레이키가 시작된다. 롤백 격리는 커밋 시점 동작(제약 지연·after-commit 훅·outbox)을 못 본다는 한계를 알고 쓴다.
- 프로덕션 데이터 복사 금지(PII) → [[개인정보와 컴플라이언스]]. 특히 외주에서는 발주사 실데이터의 테스트 환경 반입 자체가 계약·규제 사안이다.

## 시간·랜덤은 주입한다

- `now()`를 코드 깊숙이 직접 호출하면 "말일 마감·자정 경계·기한 초과" 로직은 영원히 테스트 불가다. **시계를 인터페이스로 주입**하고 테스트가 시각을 고정한다.
- 랜덤·UUID·토큰 생성도 동일 — 생성기를 주입하면 단언 가능한 결정적 테스트가 된다.
- `sleep` 기반 대기 금지 — 조건 폴링으로. 시간 의존 플레이키의 처방은 [[테스트 전략 실전]] 표 참조.

## 검수 기준과의 연결 — TC가 자동 테스트로 추적돼야 한다

- 외주 검수의 정본은 착수 전 합의된 시나리오·테스트케이스 문서다. **TC ID를 자동 테스트 이름·주석에 박아** "TC-07 = 이 테스트"가 조회로 끝나게 한다 — 검수 회의에서 "그건 테스트했는데요"는 근거가 아니다.
- 자동화가 못 덮는 TC(육안 확인·실기기)는 수동 검증 절차와 증적(스크린샷·로그)을 남긴다. 추적표의 구멍이 곧 검수 리스크 목록이다.
- 범위 밖 결함을 테스트 중 발견하면 조용히 고치지 않는다 — CR 회부가 원칙이다.

## 발주사 환경 제약 — 도구는 표준에 맞춘다

- 테스트 러너·라이브러리·컨테이너 사용 가능 여부는 발주사 표준·폐쇄망 정책에 묶일 수 있다 — **착수 시점에 확인**하고, 특정 도구 전제의 테스트 자산을 만들기 전에 실행 환경부터 검증한다.
- 제약이 심하면 언어 표준 러너 + 실DB 스키마 사본으로도 몸통은 세울 수 있다 — 도구가 아니라 "경계를 관통하는 검증"이 본질이다.
- 테스트 코드도 납품물이다: 발주사 환경에서 한 명령으로 전체 실행되는 진입점(스크립트)과 기준 통과 수를 문서화해 이관한다.

## 안티패턴

- **mock 위의 mock** — 레포지토리·서비스·클라이언트 전부 mock이면 테스트가 구현의 복사본이다. 통합 지점은 실물·가짜 서버로 → [[테스트 전략 실전]].
- **테스트 간 실행 순서 의존** — "전체 돌리면 통과, 하나만 돌리면 실패"는 이미 깨진 스위트다.
- **성공 경로만 있는 통합 테스트** — 백엔드의 값은 실패 처리에 있다. 타임아웃·중복 요청·제약 위반이 본편이다.
- **CI 없는 테스트** — 사람이 기억날 때만 도는 테스트는 회귀 방지 자산이 아니다. 전체 통과가 머지·배포 게이트여야 한다.

## 관련 문서

- [[00_백엔드 허브]] — 06_백엔드 진입점
- [[백엔드 원리]] — 도메인 분리(테스트 가능성)·실패 시나리오 우선
- [[테스트 전략 실전]] — 자원 배분·행동 테스트·플레이키 3대 원인
- [[QA 원리]] — 자동화가 못 잡는 것, 판정
- [[외부 연동과 웹훅]] — 연동 실패 시나리오의 목록
- [[개인정보와 컴플라이언스]] — 테스트 데이터의 PII
