E2E 테스트는 개별적인 코드 단위(단위 테스트)나 모듈 간의 연동(통합 테스트)을 넘어, 실제 사용자의 시나리오와 동일한 조건에서 애플리케이션의 전체 흐름을 처음부터 끝까지 테스트하는 방법입니다.
NestJS에서의 E2E 테스트:
| 테스트 종류 | 테스트 대상 | 의존성 | 실행 속도 |
|---|---|---|---|
| 단위 테스트 (Unit Test) | 서비스, 개별 함수 | Mocking (가짜 객체) | 매우 빠름 |
| E2E 테스트 (End-to-End Test) | 전체 애플리케이션 | 실제 DB, 실제 모듈 | 매우 느림 |
NestJS는 E2E 테스트를 위해 Supertest 라이브러리와 Jest 테스트 프레임워크를 기본적으로 사용합니다.
Supertest: Node.js의 HTTP 서버를 추상화하여, 실제 서버를 띄우고 HTTP 요청을 보내는 과정을 프로그래매틱하게 테스트할 수 있게 해주는 라이브러리입니다.
*.e2e-spec.ts)test 폴더에 E2E 테스트를 위한 기본 설정 파일이 자동으로 만들어집니다.beforeAll(async () => { ... }):
Test.createTestingModule({...}): 실제 AppModule과 유사한 테스트용 모듈을 생성합니다. 이 모듈은 테스트에 필요한 모든 프로바이더, 컨트롤러, 모듈을 포함합니다.app.init(): 테스트용 NestJS 애플리케이션을 초기화합니다. (서버를 띄우지는 않음)app.getHttpServer(): 초기화된 앱으로부터 HTTP 서버 인스턴스를 가져옵니다.각 테스트 케이스 (it('...', async () => { ... })):
request(app.getHttpServer()): Supertest의 request 함수에 HTTP 서버 인스턴스를 전달하여, HTTP 요청을 보낼 수 있는 클라이언트를 생성합니다.afterAll(async () => { ... }):
app.close(): 테스트용 애플리케이션을 안전하게 종료하여, 열려있는 데이터베이스 커넥션 등을 정리합니다.문제점: E2E 테스트는 실제 데이터베이스를 조작하므로, 운영 DB나 개발 DB를 그대로 사용하면 데이터가 오염되거나 삭제될 위험이 있습니다.
해결책: 테스트 전용 데이터베이스를 별도로 구성하고, 테스트 환경에서만 해당 DB에 연결하도록 설정해야 합니다.
구현 방법:
test.env 파일 생성: 테스트 환경에서 사용할 환경 변수(e.g., DB_DATABASE=test_db)를 별도의 .env 파일에 정의합니다.Test.createTestingModule에서 ConfigModule을 설정할 때, envFilePath를 test.env로 지정합니다.beforeEach 블록 등에서 테스트 실행 전에 데이터베이스를 깨끗한 상태로 초기화하는 로직(e.g., 모든 테이블 TRUNCATE)을 추가하는 것이 좋습니다.// 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();
});
});
Supertest 라이브러리를 사용하여, 실제 서버를 띄우지 않고도 HTTP 요청을 시뮬레이션하고 응답을 검증하는 E2E 테스트 환경을 기본적으로 제공합니다.beforeAll (앱 초기화) → it (개별 테스트 케이스) → afterAll (앱 종료) 순으로 진행되며, request() 함수를 통해 API를 호출하고 expect() 함수로 결과를 검증합니다.