TIL - 20260227

juni·2026년 2월 27일

TIL

목록 보기
279/318

0227 NestJS 기초 (9/N): E2E 테스트와 Supertest


✅ 1. E2E (End-to-End) 테스트란?

  • E2E 테스트는 개별적인 코드 단위(단위 테스트)나 모듈 간의 연동(통합 테스트)을 넘어, 실제 사용자의 시나리오와 동일한 조건에서 애플리케이션의 전체 흐름을 처음부터 끝까지 테스트하는 방법입니다.

  • NestJS에서의 E2E 테스트:

    • 실제 HTTP 요청을 보내고, 미들웨어, 가드, 파이프, 인터셉터, 컨트롤러, 서비스, 데이터베이스까지 모든 계층을 거쳐 반환된 실제 HTTP 응답을 검증하는 것을 의미합니다.
    • 목표: 애플리케이션의 모든 부분이 유기적으로 잘 동작하는지를 종합적으로 보증하는 것.
테스트 종류테스트 대상의존성실행 속도
단위 테스트 (Unit Test)서비스, 개별 함수Mocking (가짜 객체)매우 빠름
E2E 테스트 (End-to-End Test)전체 애플리케이션실제 DB, 실제 모듈매우 느림

✅ 2. NestJS의 E2E 테스트 환경

  • NestJS는 E2E 테스트를 위해 Supertest 라이브러리와 Jest 테스트 프레임워크를 기본적으로 사용합니다.

  • Supertest: Node.js의 HTTP 서버를 추상화하여, 실제 서버를 띄우고 HTTP 요청을 보내는 과정을 프로그래매틱하게 테스트할 수 있게 해주는 라이브러리입니다.

➕ E2E 테스트의 실행 흐름 (*.e2e-spec.ts)

  • NestJS CLI로 프로젝트를 생성하면, test 폴더에 E2E 테스트를 위한 기본 설정 파일이 자동으로 만들어집니다.
  1. beforeAll(async () => { ... }):

    • 본격적인 테스트가 실행되기 전에 단 한 번 실행되는 블록입니다.
    • Test.createTestingModule({...}): 실제 AppModule과 유사한 테스트용 모듈을 생성합니다. 이 모듈은 테스트에 필요한 모든 프로바이더, 컨트롤러, 모듈을 포함합니다.
    • app.init(): 테스트용 NestJS 애플리케이션을 초기화합니다. (서버를 띄우지는 않음)
    • app.getHttpServer(): 초기화된 앱으로부터 HTTP 서버 인스턴스를 가져옵니다.
  2. 각 테스트 케이스 (it('...', async () => { ... })):

    • request(app.getHttpServer()): Supertestrequest 함수에 HTTP 서버 인스턴스를 전달하여, HTTP 요청을 보낼 수 있는 클라이언트를 생성합니다.
    • .get('/'), .post('/auth/login') 등: 실제 HTTP 요청을 보냅니다.
    • .send({ ... }): 요청의 본문(body) 데이터를 설정합니다.
    • .expect(200), .expect(403): 응답의 HTTP 상태 코드를 검증합니다.
    • .expect(res => { ... }): 응답의 본문(body)이나 헤더(header)의 상세 내용을 검증합니다.
  3. afterAll(async () => { ... }):

    • 모든 테스트가 완료된 후 단 한 번 실행되는 블록입니다.
    • app.close(): 테스트용 애플리케이션을 안전하게 종료하여, 열려있는 데이터베이스 커넥션 등을 정리합니다.

✅ 3. 테스트 데이터베이스 분리

  • 문제점: E2E 테스트는 실제 데이터베이스를 조작하므로, 운영 DB나 개발 DB를 그대로 사용하면 데이터가 오염되거나 삭제될 위험이 있습니다.

  • 해결책: 테스트 전용 데이터베이스를 별도로 구성하고, 테스트 환경에서만 해당 DB에 연결하도록 설정해야 합니다.

  • 구현 방법:

    1. test.env 파일 생성: 테스트 환경에서 사용할 환경 변수(e.g., DB_DATABASE=test_db)를 별도의 .env 파일에 정의합니다.
    2. 테스트 모듈 설정 수정: Test.createTestingModule에서 ConfigModule을 설정할 때, envFilePathtest.env로 지정합니다.
    3. DB 초기화: 각 테스트가 서로에게 영향을 주지 않도록, beforeEach 블록 등에서 테스트 실행 전에 데이터베이스를 깨끗한 상태로 초기화하는 로직(e.g., 모든 테이블 TRUNCATE)을 추가하는 것이 좋습니다.

✅ 4. E2E 테스트 작성 예시

// app.e2e-spec.ts
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { AppModule } from './../src/app.module';
import { INestApplication, ValidationPipe } from '@nestjs/common';

describe('AppController (e2e)', () => {
  let app: INestApplication;

  // 1. 테스트 전, 테스트용 앱 초기화
  beforeAll(async () => {
    const moduleFixture = await Test.createTestingModule({
      imports: [AppModule], // 실제 앱 모듈을 그대로 사용
    }).compile();

    app = moduleFixture.createNestApplication();
    // 실제 앱과 동일하게 전역 파이프 등도 설정해주어야 함
    app.useGlobalPipes(new ValidationPipe());
    await app.init();
  });

  // 2. 테스트 케이스 작성
  it('/ (GET)', () => {
    return request(app.getHttpServer()) // Supertest로 요청 클라이언트 생성
      .get('/') // GET / 요청
      .expect(200) // 상태 코드가 200인지 검증
      .expect('Hello World!'); // 응답 본문이 'Hello World!'인지 검증
  });

  it('/movies (POST) - 유효성 검증 실패', () => {
    return request(app.getHttpServer())
      .post('/movies')
      .send({ title: 'Test Movie' }) // year 필드 누락
      .expect(400); // ValidationPipe에 의해 400 Bad Request가 발생하는지 검증
  });

  // 3. 모든 테스트 후, 앱 종료
  afterAll(async () => {
    await app.close();
  });
});

📌 요약

  • E2E 테스트는 실제 사용자의 관점에서 애플리케이션의 전체 흐름을 검증하는 가장 높은 수준의 테스트입니다.
  • NestJS는 Supertest 라이브러리를 사용하여, 실제 서버를 띄우지 않고도 HTTP 요청을 시뮬레이션하고 응답을 검증하는 E2E 테스트 환경을 기본적으로 제공합니다.
  • E2E 테스트는 실제 데이터베이스에 영향을 주므로, 반드시 테스트 전용 데이터베이스를 분리하여 사용해야 합니다.
  • 테스트의 실행 순서는 beforeAll (앱 초기화) → it (개별 테스트 케이스) → afterAll (앱 종료) 순으로 진행되며, request() 함수를 통해 API를 호출하고 expect() 함수로 결과를 검증합니다.

0개의 댓글