방명록
- Node.js + MySQL 기반 REST API 통합 테스트 완벽 튜터리얼2025년 07월 26일 23시 16분 58초에 업로드 된 글입니다.작성자: DandyNow728x90반응형
Node.js + MySQL 기반 REST API 통합 테스트 완벽 튜터리얼
1. 통합 테스트란 무엇인가? 왜 필요한가?
- 통합 테스트(Integration Test)란, 여러 컴포넌트(예: 라우터, 컨트롤러, DB 등)가 실제 환경처럼 잘 연결되어 동작하는지 검증하는 테스트이다.
- 단위 테스트(Unit Test)는 개별 함수나 모듈만 검증하지만, 통합 테스트는 실제 서버를 띄우고 HTTP 요청을 보내 전체 시스템의 흐름을 검증한다.
- 필요성
- 실제 배포 환경과 유사하게 동작하는지 미리 확인할 수 있다.
- 라우터, 미들웨어, DB 등 여러 계층이 올바르게 연결되어 있는지 한 번에 검증할 수 있다.
- 예외 상황(없는 데이터, 잘못된 요청 등)도 실제처럼 테스트할 수 있다.
2. Node.js에서 통합 테스트 구성 방법
2-1. 필요한 라이브러리
- express: 서버 프레임워크
- mysql2: MySQL 데이터베이스 드라이버
- supertest: HTTP 요청을 시뮬레이션하여 실제 서버에 테스트 요청을 보냄
- jest: 테스트 러너
설치 명령어:
npm install express mysql2 supertest jest
2-2. MySQL 데이터베이스 준비
- 테스트용 데이터베이스와 products 테이블을 미리 생성해두자.
CREATE DATABASE testdb; USE testdb; CREATE TABLE products ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT NOT NULL );
3. Node.js + MySQL API 서버 코드
3-1. DB 연결 설정 (
db.js)// db.js const mysql = require("mysql2/promise"); const pool = mysql.createPool({ host: "localhost", user: "root", password: "비밀번호", // 본인 환경에 맞게 수정 database: "testdb", waitForConnections: true, connectionLimit: 10, queueLimit: 0, }); module.exports = pool;
3-2. Product 모델 함수 (
models/Product.js)// models/Product.js const db = require("../db"); exports.createProduct = async (product) => { const [result] = await db.query( "INSERT INTO products (name, description) VALUES (?, ?)", [product.name, product.description] ); return { id: result.insertId, ...product }; }; exports.getAllProducts = async () => { const [rows] = await db.query("SELECT * FROM products"); return rows; }; exports.getProductById = async (id) => { const [rows] = await db.query("SELECT * FROM products WHERE id = ?", [id]); return rows[0]; }; exports.updateProduct = async (id, product) => { await db.query("UPDATE products SET name = ?, description = ? WHERE id = ?", [ product.name, product.description, id, ]); return { id, ...product }; }; exports.deleteProduct = async (id) => { await db.query("DELETE FROM products WHERE id = ?", [id]); };
3-3. Express 라우터 및 서버 (
controller/products.js,server.js)// controller/products.js const express = require("express"); const router = express.Router(); const Product = require("../models/Product"); router.post("/products", async (req, res) => { try { const product = await Product.createProduct(req.body); res.status(201).json(product); } catch (err) { res.status(500).json({ message: err.message }); } }); router.get("/products", async (req, res) => { const products = await Product.getAllProducts(); res.json(products); }); router.get("/products/:id", async (req, res) => { const product = await Product.getProductById(req.params.id); if (!product) return res.status(404).json({ message: "Not found" }); res.json(product); }); router.put("/products/:id", async (req, res) => { const product = await Product.getProductById(req.params.id); if (!product) return res.status(404).json({ message: "Not found" }); const updated = await Product.updateProduct(req.params.id, req.body); res.json(updated); }); router.delete("/products/:id", async (req, res) => { const product = await Product.getProductById(req.params.id); if (!product) return res.status(404).json({ message: "Not found" }); await Product.deleteProduct(req.params.id); res.status(200).json({ message: "Deleted" }); }); module.exports = router;// server.js const express = require("express"); const app = express(); const productRouter = require("./controller/products"); app.use(express.json()); app.use("/api", productRouter); const server = app.listen(3000, () => { console.log("Server started"); }); module.exports = server;
4. 통합 테스트 코드 작성 (
test/integration/products.int.test.js)4-1. 테스트 코드 전체 예시
const request = require("supertest"); const server = require("../../server"); const db = require("../../db"); let firstProduct; beforeAll(async () => { // 테스트 시작 전 products 테이블 비우기 await db.query("DELETE FROM products"); }); afterAll(async () => { await server.close(); await db.end(); }); it("POST /api/products - 제품 생성", async () => { const newProduct = { name: "테스트상품", description: "설명" }; const response = await request(server).post("/api/products").send(newProduct); expect(response.statusCode).toBe(201); expect(response.body.name).toBe(newProduct.name); expect(response.body.description).toBe(newProduct.description); }); it("GET /api/products - 전체 제품 조회", async () => { const response = await request(server).get("/api/products"); expect(response.statusCode).toBe(200); expect(Array.isArray(response.body)).toBeTruthy(); firstProduct = response.body[0]; }); it("GET /api/products/:id - 개별 제품 조회", async () => { const response = await request(server).get( `/api/products/${firstProduct.id}` ); expect(response.statusCode).toBe(200); expect(response.body.name).toBe(firstProduct.name); }); it("PUT /api/products/:id - 제품 수정", async () => { const response = await request(server) .put(`/api/products/${firstProduct.id}`) .send({ name: "수정상품", description: "수정설명" }); expect(response.statusCode).toBe(200); expect(response.body.name).toBe("수정상품"); }); it("DELETE /api/products/:id - 제품 삭제", async () => { const response = await request(server).delete( `/api/products/${firstProduct.id}` ); expect(response.statusCode).toBe(200); });
4-2. 코드 설명
beforeAll: 테스트 시작 전 products 테이블을 비워, 항상 동일한 상태에서 테스트가 시작되도록 한다.
afterAll: 테스트가 끝나면 서버와 DB 연결을 종료한다.
각 테스트 케이스
POST /api/products: 제품을 생성하고, 응답에 올바른 데이터가 담겼는지 확인GET /api/products: 전체 제품 목록을 배열로 반환하는지 확인GET /api/products/:id: 특정 id의 제품 정보를 정확히 반환하는지 확인PUT /api/products/:id: 제품 정보가 정상적으로 수정되는지 확인DELETE /api/products/:id: 제품이 정상적으로 삭제되는지 확인
supertest를 사용하여 실제 서버에 HTTP 요청을 보내고, 응답을 검증한다.
이로써 라우터, 컨트롤러, DB까지 전체 시스템이 실제 환경처럼 동작하는지 확인할 수 있다.
5. 마치며
- 통합 테스트는 실제 서버와 DB가 연동된 환경에서 API가 올바르게 동작하는지,
그리고 예외 상황도 잘 처리되는지 한 번에 검증할 수 있는 강력한 도구이다. - Node.js에서는 supertest, jest, mysql2 등을 활용해 쉽게 통합 테스트 환경을 구축할 수 있다.
- 실제 서비스에 배포하기 전, 반드시 통합 테스트를 통해 전체 시스템의 신뢰성을 확보하자!
VSCode Extention
Jest Runner(firsttris)를 이용하면 편리한 테스트 환경을 구성할 수 있다.728x90반응형'언어·프레임워크 > Node.js' 카테고리의 다른 글
[Node.js] npm과 npx의 차이점과 사용법 (1) 2025.08.08 Node.js + MySQL 기반 REST API 단위 테스트 실습 튜터리얼 (2) 2025.07.26 [Node.js] Jest 경로 전쟁: 복잡한 설정 대신 구조로 해결하기 (2) 2025.07.25 사용자 경험을 해치지 않는 봇 방어: 클라우드플레어 턴스타일(Cloudflare Turnstile)의 이해와 활용 (0) 2025.07.05 [Node.js] 배치 프로그램에 강력한 로깅, Winston 적용하기 (1) 2025.06.04 다음글이 없습니다.이전글이 없습니다.댓글