본문으로 건너뛰기

테스트

본 문서는 무엇을 어느 수준에서 검증하는지, 그리고 각 수준에서 무엇을 하지 않는지를 정의합니다.

1. 세 수준

수준 도구 검증 대상 실행 환경
단위 Vitest 순수 함수, 도메인 규칙, 스키마 검증 Node
컴포넌트 Vitest + TestBed 컴포넌트의 입출력, 상태 전이, 조건부 표시 jsdom
E2E Playwright 화면 간 흐름, 라우팅·가드·인터셉터 조합 실제 브라우저

수준을 나누는 기준은 무엇이 깨졌을 때 알아야 하는가입니다. 계산이 틀린 것은 단위가, 화면이 잘못 그려지는 것은 컴포넌트가, 화면을 넘어가며 무언가 어긋나는 것은 E2E가 잡습니다.

2. 단위 테스트

2.1 대상

필수 선택
도메인 규칙 계산 (등급 산출, 금액 계산) 단순 포맷 함수
폼 스키마의 검증 규칙
날짜·수치 변환 유틸
상태 전이 로직 (model 세그먼트)

분기가 있는 코드는 필수입니다. 분기가 없는 한 줄짜리 위임 함수는 대상이 아닙니다.

2.2 하지 않는 것

  • Angular 프레임워크 자체의 동작 검증
  • 생성된 서버 타입의 구조 검증
  • httpResource가 요청을 보내는지 여부

프레임워크와 생성물은 우리가 만든 것이 아닙니다. 이들을 테스트하면 프레임워크 버전이 올라갈 때마다 테스트가 깨집니다.

3. 컴포넌트 테스트

3.1 대상

필수 이유
적응형 컴포넌트의 두 모드 pointertouch 각각. 한쪽만 검증하면 다른 쪽은 실기기에서만 발견됩니다
조건부 표시가 있는 컴포넌트 로딩·에러·빈 상태·정상 상태의 분기
폼 컴포넌트 검증 실패 시 오류 표시와 접근성 속성
출력 이벤트 사용자 동작에 대해 올바른 출력이 발생하는지

3.2 적응형 컴포넌트

BreakpointObserver를 대체 구현으로 주입해 두 모드를 각각 검증합니다.

function withInteractionMode(mode: 'pointer' | 'touch') {
  return {
    provide: BreakpointObserver,
    useValue: {
      observe: () => of({
        matches: mode === 'touch',
        breakpoints: {
          '(pointer: coarse)': mode === 'touch',
          '(hover: none)': mode === 'touch',
        },
      }),
    },
  };
}

자동 강제 수단이 없으므로 코드 리뷰에서 두 테스트의 존재를 확인합니다.

3.3 검증 방식

구분 준수 지침 (Do) 금지 지침 (Don't)
요소 선택 역할과 접근 가능한 이름으로 찾습니다 CSS 클래스나 data-testid에 의존합니다
검증 대상 사용자가 보고 조작하는 결과 내부 필드값이나 private 메서드
비동기 대기 상태가 확정될 때까지 기다립니다 고정 시간 setTimeout

역할로 요소를 찾으면 테스트가 접근성 검증을 겸합니다. 접근 가능한 이름이 없으면 테스트에서 요소를 찾지 못하므로 누락이 드러납니다.

3.4 HTTP 목킹

HttpTestingController를 사용합니다. 실제 네트워크를 사용하지 않습니다.

응답 목은 생성된 서버 타입으로 작성합니다. 임의 객체를 쓰면 서버 계약이 바뀌어도 테스트가 통과합니다.

4. E2E 테스트

4.1 대상

핵심 흐름만 다룹니다. 화면 개수만큼 E2E를 만들지 않습니다.

대상 이유
로그인부터 주요 업무 완료까지의 흐름 라우팅·가드·인터셉터·토큰 갱신이 조합된 상태는 다른 수준에서 검증 불가
인증 만료 시 로그인 이동 인터셉터와 라우터의 협력
터치 조건에서의 적응형 UI jsdom은 실제 포인터 조건을 재현하지 못합니다

Playwright의 컨텍스트 옵션으로 터치 조건을 재현합니다.

test.use({ hasTouch: true, isMobile: true });

4.2 하지 않는 것

  • 개별 컴포넌트의 표시 검증 (컴포넌트 테스트가 담당)
  • 검증 규칙의 모든 경우 (단위 테스트가 담당)
  • 모든 화면의 스모크 테스트

E2E는 느리고 불안정합니다. 다른 수준에서 검증 가능한 것을 E2E로 올리면 비용만 늘어납니다.

4.3 안정성

규칙 내용
대기 방식 Playwright의 자동 대기를 사용합니다. 고정 시간 대기를 금지합니다
테스트 간 독립 각 테스트가 자신의 상태를 준비합니다. 실행 순서에 의존하지 않습니다
불안정 테스트 재시도로 덮지 않습니다. 원인을 찾거나 삭제합니다

재시도로 통과시킨 불안정 테스트는 실제 결함을 숨깁니다. 원인을 찾을 수 없으면 삭제하는 편이 낫습니다.

5. 커버리지

수치 목표를 설정하지 않습니다.

커버리지는 실행된 줄의 비율이며 검증의 품질을 나타내지 않습니다. 목표 수치를 강제하면 통과만 시키는 테스트를 작성하게 됩니다.

대신 2절·3절대상 목록을 기준으로 삼습니다. 무엇을 테스트했는지가 얼마나 테스트했는지보다 중요합니다.

커버리지 보고서는 생성하되, 게이트로 사용하지 않고 누락 탐색 도구로만 사용합니다.

6. 실행

npm test              # 단위 + 컴포넌트
npx playwright test   # E2E
시점 실행 대상
로컬 개발 단위 + 컴포넌트
PR 단위 + 컴포넌트 + E2E
배포 전 전체

E2E를 로컬 필수로 두지 않는 이유는 실행 시간 때문입니다. PR 단계에서 CI가 담당합니다.

7. 배치

테스트 파일은 대상 파일 옆에 둡니다.

pages/assessment-list/
├── ui/
│   ├── assessment-list.ts
│   └── assessment-list.spec.ts
└── model/
    ├── assessment-list.ts
    └── assessment-list.spec.ts

E2E는 계층에 속하지 않으므로 저장소 루트의 e2e/에 둡니다.

별도 __tests__ 디렉터리를 만들지 않습니다. 대상과 테스트가 떨어져 있으면 코드를 옮길 때 테스트가 따라오지 않습니다.

8. 수동 확인

자동화되지 않는 항목입니다. 화면 완성 시와 릴리스 전에 확인합니다.

항목 시점
마우스 없이 키보드만으로 주요 흐름 완주 화면 완성 시
스크린리더로 주요 흐름 확인 릴리스 전
라이트·다크 양쪽의 색 대비 토큰 변경 시
실기기에서의 적응형 UI 동작 적응형 컴포넌트 추가 시

9. 금지 사항

금지 사유
커버리지 수치를 게이트로 사용 통과만 시키는 테스트를 유도합니다
프레임워크 동작 검증 버전이 올라갈 때마다 깨집니다
CSS 클래스로 요소 선택 스타일 변경에 테스트가 깨집니다
고정 시간 대기 느리고 불안정합니다
불안정 테스트를 재시도로 통과 실제 결함을 숨깁니다
임의 객체로 응답 목 작성 계약 변경을 검출하지 못합니다
모든 화면에 E2E 작성 실행 시간과 유지 비용이 급증합니다
__tests__ 디렉터리 분리 코드 이동 시 테스트가 남겨집니다
© 2026 dev.goraebap