단순히 함수만 테스트하는 유닛 테스트가 아니라, 실제 API 호출 흐름을 따라가며 서버 전체의 응답을 확인하는 테스트 방식이다.
이럴 때 사용하는 도구가 바로 Jest + Supertest 조합이다.
테스트를 설계할 때 그냥 막연히 작성하지 않고, “어떤 상황에서 어떤 결과를 기대할지”를 명확히 정해두는 게 중요하다.
이걸 테스트 시나리오라고 한다.
예를 들어 회원가입 API를 테스트한다고 하면:
상황: 모든 입력이 정상적으로 들어왔을 때
행동: 회원가입 요청을 보낸다
기대 결과: 201 응답 코드와 “회원가입 성공” 메시지
또는 이메일이 중복된 경우라면:
상황: 이미 존재하는 이메일
행동: 같은 이메일로 회원가입 시도
기대 결과: 400 응답 코드와 “이메일 중복” 메시지
이런 시나리오를 미리 정리해두면 테스트 설계가 훨씬 체계적으로 진행된다.
테스트를 진행하려면 먼저 필요한 패키지를 설치해야 한다:
npm install --save-dev jest @types/jest ts-jest
npm install --save-dev supertest @types/supertest
그 다음 package.json
에 테스트 실행 스크립트를 등록한다.
"test": "dotenv -e .env.test -- npm run prisma:migrate && dotenv -e .env.test -- jest"
이 스크립트를 통해 .env.test를 기반으로 마이그레이션 후 테스트를 실행할 수 있다.
app.listen()
이 포함된 코드와 Express 앱 정의 코드를 분리해두면,app
객체를 테스트 코드에서 사용할 수 있어 매우 유용하다.// app.js
const app = express();
export default app;
Supertest는 실제로 HTTP 요청을 보내진 않지만, 마치 보내는 것처럼 서버의 응답을 시뮬레이션해주는 라이브러리다.
.get(), .post(), .put(), .delete() 등의 HTTP 메서드 사용 가능
.send()로 바디, .query()로 쿼리 파라미터, .set()으로 헤더 설정
응답 객체의 .status, .body, .headers 등 확인 가능
const res = await request(app).post('/api/signup').send({ email, password })
expect(res.status).toBe(201)
인증처럼 세션이나 쿠키가 필요한 연속된 요청을 테스트할 때 사용
예: 로그인 → 인증된 상태로 다른 API 요청
const agent = request.agent(app)
await agent.post('/login').send(credentials)
await agent.get('/profile') // 쿠키 유지됨
통합 테스트에서는 다음 작업들을 신경 써야 한다:
Setup / Teardown
테스트 전 DB 초기화 필요
테스트 후 정리 작업 (DB truncate 등)
병렬 실행 주의
--runInBand
옵션을 줘서 순차 실행하도록 설정한다:npx jest --runInBand
항목 | 설명 |
---|---|
테스트 시나리오 | 상황, 행동, 예상 결과로 구성 |
테스트 DB | .env.test 와 dotenv-cli 사용 |
app 객체 분리 | 테스트에서 서버 없이 app만 사용 |
Supertest | HTTP 요청 시뮬레이션 도구 |
request vs agent | 단발 요청 vs 세션 유지 요청 |
병렬 문제 | --runInBand 옵션으로 해결 가능 |
처음에는 "API 테스트는 그냥 Postman으로 하면 되지 않나?" 생각했지만,
자동화된 테스트는 협업과 리팩토링, 유지보수에 있어 정말 강력한 도구라는 걸 깨달았다.
특히 agent를 써서 로그인 후 동작을 테스트하거나, 테스트용 DB를 따로 분리하는 방법은 실제 현업에서도 유용하게 쓰일 수 있을 것 같다.
이번에는 테스트 기본기를 쌓는 기초 단계였고,
다음에는 실제로 JWT 인증된 API를 테스트하거나, 테스트 데이터를 동적으로 생성하는 방법도 더 연습해봐야겠다.