단위 테스트는 코드의 작은 부분을 검사하여 제대로 작동하는지 확인하고 버그를 조기에 발견하기 때문에 중요합니다. 앱을 출시하기 전에 이러한 테스트를 수행하는 것이 중요합니다. 이 가이드에서는 Mocha와 Chai를 사용한 단위 테스트를 다룹니다.
Mocha는 Node.js에서 실행되는 기능이 풍부한 JavaScript 테스트 프레임워크로, 비동기 테스트를 간단하고 즐겁게 만듭니다. 특정 순서에 따라 실행되어 테스트 결과를 수집하고 정확한 보고를 제공하는 기능을 제공합니다.
Chai는 모든 JavaScript 테스트 프레임워크와 함께 사용할 수 있는 BDD/TDD 어설션 라이브러리입니다. 다양한 인터페이스를 제공하므로 개발자는 가장 편안하다고 생각하는 어설션 스타일을 선택할 수 있습니다.
읽기 쉽고 표현이 풍부한 주장
Chai는 Mocha와 잘 작동하는 다양한 어설션 스타일과 구문 옵션을 제공하므로 명확성과 가독성을 위해 필요에 맞는 스타일을 선택할 수 있습니다.
비동기 테스트 지원
Mocha는 비동기 테스트를 쉽게 처리하므로 추가 라이브러리나 복잡한 설정 없이 Node.js 애플리케이션에서 비동기 코드를 테스트할 수 있습니다.
먼저 새 Node.js 프로젝트를 설정하고 필요한 종속성을 설치해 보겠습니다.
mkdir auth-api-testing cd auth-api-testing npm init -y # Install production dependencies npm install express jsonwebtoken mongoose bcryptjs dotenv # Install development dependencies npm install --save-dev mocha chai chai-http supertest nyc
package.json에 다음 스크립트를 추가하세요.
{ "scripts": { "test": "NODE_ENV=test mocha --timeout 10000 --exit", "test:coverage": "nyc npm test" } }
테스트에 들어가기 전에 테스트할 애플리케이션에 대해 알아보겠습니다. 다음과 같은 기능으로 간단하면서도 안전한 인증 API를 구축하고 있습니다.
src/ ├── models/ │ └── user.model.js # User schema and model ├── routes/ │ ├── auth.routes.js # Authentication routes │ └── user.routes.js # User management routes ├── middleware/ │ ├── auth.middleware.js # JWT verification middleware │ └── validate.js # Request validation middleware ├── controllers/ │ ├── auth.controller.js # Authentication logic │ └── user.controller.js # User management logic └── app.js # Express application setup
POST /api/auth/register - Registers new user - Accepts: { email, password, name } - Returns: { token, user } POST /api/auth/login - Authenticates existing user - Accepts: { email, password } - Returns: { token, user }
GET /api/users/profile - Gets current user profile - Requires: JWT Authentication - Returns: User object PUT /api/users/profile - Updates user profile - Requires: JWT Authentication - Accepts: { name, email } - Returns: Updated user object
테스트별 구성을 위한 .env.test 파일을 생성합니다.
PORT=3001 MONGODB_URI=mongodb://localhost:27017/auth-api-test JWT_SECRET=your-test-secret-key
첫 번째 테스트 파일 test/auth.test.js를 만들어 보겠습니다
const chai = require('chai'); const chaiHttp = require('chai-http'); const app = require('../src/app'); const User = require('../src/models/user.model'); chai.use(chaiHttp); const expect = chai.expect; describe('Auth API Tests', () => { // Runs before all tests before(async () => { await User.deleteMany({}); }); // Runs after each test afterEach(async () => { await User.deleteMany({}); }); // Test suites will go here });
Mocha는 테스트 설정 및 정리를 위한 여러 후크를 제공합니다.
before(): 모든 테스트 전에 한 번 실행
after(): 모든 테스트 후에 한 번 실행
beforeEach(): 각 테스트 전에 실행
afterEach(): 각 테스트 후에 실행
테스트는 관련 테스트를 그룹화하는 데 explain() 블록을 사용하고 개별 테스트 사례에는 it() 블록을 사용하여 구성됩니다.
mkdir auth-api-testing cd auth-api-testing npm init -y # Install production dependencies npm install express jsonwebtoken mongoose bcryptjs dotenv # Install development dependencies npm install --save-dev mocha chai chai-http supertest nyc
{ "scripts": { "test": "NODE_ENV=test mocha --timeout 10000 --exit", "test:coverage": "nyc npm test" } }
src/ ├── models/ │ └── user.model.js # User schema and model ├── routes/ │ ├── auth.routes.js # Authentication routes │ └── user.routes.js # User management routes ├── middleware/ │ ├── auth.middleware.js # JWT verification middleware │ └── validate.js # Request validation middleware ├── controllers/ │ ├── auth.controller.js # Authentication logic │ └── user.controller.js # User management logic └── app.js # Express application setup
POST /api/auth/register - Registers new user - Accepts: { email, password, name } - Returns: { token, user } POST /api/auth/login - Authenticates existing user - Accepts: { email, password } - Returns: { token, user }
GET /api/users/profile - Gets current user profile - Requires: JWT Authentication - Returns: User object PUT /api/users/profile - Updates user profile - Requires: JWT Authentication - Accepts: { name, email } - Returns: Updated user object
각 테스트는 독립적이어야 하며 다른 테스트에 의존해서는 안 됩니다
테스트는 어떤 순서로도 실행될 수 있어야 합니다
올바른 설정 및 정리를 위해 before, after, beforeEach 및 afterEach 후크를 사용하세요
PORT=3001 MONGODB_URI=mongodb://localhost:27017/auth-api-test JWT_SECRET=your-test-secret-key
const chai = require('chai'); const chaiHttp = require('chai-http'); const app = require('../src/app'); const User = require('../src/models/user.model'); chai.use(chaiHttp); const expect = chai.expect; describe('Auth API Tests', () => { // Runs before all tests before(async () => { await User.deleteMany({}); }); // Runs after each test afterEach(async () => { await User.deleteMany({}); }); // Test suites will go here });
경계 조건, 오류 시나리오, 잘못된 입력, 비어 있거나 null 값을 테스트합니다.
describe('Auth API Tests', () => { describe('POST /api/auth/register', () => { it('should register a new user successfully', async () => { // Test implementation }); it('should return error when email already exists', async () => { // Test implementation }); }); });
테스트 이름은 테스트 중인 시나리오를 명확하게 설명하고, 일관된 명명 규칙을 따르고, 예상되는 동작을 포함해야 합니다.
describe('POST /api/auth/register', () => { it('should register a new user successfully', async () => { const res = await chai .request(app) .post('/api/auth/register') .send({ email: 'test@example.com', password: 'Password123!', name: 'Test User' }); expect(res).to.have.status(201); expect(res.body).to.have.property('token'); expect(res.body).to.have.property('user'); expect(res.body.user).to.have.property('email', 'test@example.com'); }); it('should return 400 when email already exists', async () => { // First create a user await chai .request(app) .post('/api/auth/register') .send({ email: 'test@example.com', password: 'Password123!', name: 'Test User' }); // Try to create another user with same email const res = await chai .request(app) .post('/api/auth/register') .send({ email: 'test@example.com', password: 'Password123!', name: 'Test User 2' }); expect(res).to.have.status(400); expect(res.body).to.have.property('error'); }); });
describe('Protected Routes', () => { let token; let userId; beforeEach(async () => { // Create a test user and get token const res = await chai .request(app) .post('/api/auth/register') .send({ email: 'test@example.com', password: 'Password123!', name: 'Test User' }); token = res.body.token; userId = res.body.user._id; }); it('should get user profile with valid token', async () => { const res = await chai .request(app) .get('/api/users/profile') .set('Authorization', `Bearer ${token}`); expect(res).to.have.status(200); expect(res.body).to.have.property('email', 'test@example.com'); }); it('should return 401 with invalid token', async () => { const res = await chai .request(app) .get('/api/users/profile') .set('Authorization', 'Bearer invalid-token'); expect(res).to.have.status(401); }); });
const mongoose = require('mongoose'); before(async () => { await mongoose.connect(process.env.MONGODB_URI_TEST); }); after(async () => { await mongoose.connection.dropDatabase(); await mongoose.connection.close(); });
describe('User CRUD Operations', () => { it('should update user profile', async () => { const res = await chai .request(app) .put(`/api/users/${userId}`) .set('Authorization', `Bearer ${token}`) .send({ name: 'Updated Name' }); expect(res).to.have.status(200); expect(res.body).to.have.property('name', 'Updated Name'); }); it('should delete user account', async () => { const res = await chai .request(app) .delete(`/api/users/${userId}`) .set('Authorization', `Bearer ${token}`); expect(res).to.have.status(200); // Verify user is deleted const user = await User.findById(userId); expect(user).to.be.null; }); });
chai를 사용하여 mocha에 대한 수동 테스트 사례를 작성하는 것은 효과적이지만 종종 몇 가지 문제가 있습니다.
시간 소모적: 특히 대규모 코드베이스의 경우 상세한 테스트 스위트를 직접 만드는 데 많은 시간이 걸릴 수 있습니다.
유지 관리 어려움: 애플리케이션이 변경됨에 따라 수동 테스트 업데이트 및 유지 관리가 더욱 복잡해지고 오류가 발생하기 쉽습니다.
일관되지 않은 적용 범위: 개발자는 주요 경로, 누락된 엣지 케이스 또는 프로덕션에서 버그를 일으킬 수 있는 오류 시나리오에 집중할 수 있습니다.
기술 의존적: 수동 테스트의 품질과 효율성은 개발자의 테스트 기술과 코드베이스에 대한 익숙함에 크게 좌우됩니다.
반복적이고 지루함: 여러 구성 요소나 기능에 대해 유사한 테스트 구조를 작성하는 것은 지루할 수 있으며 세부 사항에 대한 주의가 덜해질 수 있습니다.
피드백 지연: 수동 테스트 작성에 필요한 시간으로 인해 개발 속도가 느려지고 코드 품질 및 기능에 대한 중요한 피드백이 지연될 수 있습니다.
이러한 문제를 해결하기 위해 Keploy는 AI를 사용하여 테스트 프로세스를 자동화하고 개선하는 ut-gen을 도입했습니다. 이는 코드 의미를 이해하고 의미 있는 단위 테스트를 생성하는 Meta LLM 연구 논문의 첫 번째 구현입니다.
철저한 단위 테스트를 신속하게 제작하여 단위 테스트 생성(UTG)을 자동화하는 것을 목표로 합니다. 이를 통해 반복적인 수동 작업의 필요성이 줄어들고, 종종 수동으로 놓칠 수 있는 더 복잡한 시나리오를 처리하도록 테스트를 확장하여 극단적인 사례를 개선하며, 코드베이스가 커짐에 따라 전체 적용 범위를 보장하기 위해 테스트 범위가 늘어납니다.
%[https://marketplace.visualstudio.com/items?itemName=Keploy.keployio]
UTG(단위 테스트 생성) 자동화: 포괄적인 단위 테스트를 신속하게 생성하고 중복된 수동 작업을 줄입니다.
특수 사례 개선: 수동으로 놓치기 쉬운 더 복잡한 시나리오를 포괄하도록 테스트 범위를 확장하고 개선합니다.
테스트 커버리지 강화: 코드베이스가 커짐에 따라 철저한 커버리지 보장이 가능해졌습니다.
결론적으로 Mocha 및 Chai를 사용한 Node.js 백엔드 테스트를 마스터하는 것은 애플리케이션이 안정적이고 강력해지기를 원하는 개발자에게 중요합니다. Mocha의 테스트 프레임워크와 Chai의 명확한 어설션 라이브러리를 사용하여 개발자는 간단한 단위 테스트부터 복잡한 비동기 작업까지 코드의 많은 부분을 포괄하는 상세한 테스트 모음을 만들 수 있습니다. 테스트에 집중하고, 명확한 이름을 사용하고, 약속을 올바르게 처리하는 등의 모범 사례를 따르면 테스트 프로세스가 크게 향상됩니다. 개발 워크플로에서 이러한 도구와 기술을 사용하면 버그를 조기에 발견하고, 코드 품질을 개선하며, 보다 안전하고 효율적인 애플리케이션을 제공할 수 있습니다.
둘 다 테스트 도구이기는 하지만 용도가 다릅니다. Mocha는 테스트를 구성하고 실행하기 위한 구조를 제공하는 테스트 프레임워크입니다(describe() 및 it() 블록 사용). Chai는 결과를 확인하기 위한 함수(예: Expect(), Should 및 Assert)를 제공하는 Assertion 라이브러리입니다. Chai 없이도 Mocha를 사용할 수 있지만 함께 사용하면 더욱 완벽하고 표현력이 풍부한 테스트 솔루션을 얻을 수 있습니다.
Mocha는 테스트 데이터 관리를 위한 여러 수명 주기 후크를 제공합니다.
before(): 모든 테스트 전에 한 번 실행
beforeEach(): 각 테스트 전에 실행
afterEach(): 각 테스트 후에 실행
after(): 모든 테스트 후 한 번 실행
예:
mkdir auth-api-testing cd auth-api-testing npm init -y # Install production dependencies npm install express jsonwebtoken mongoose bcryptjs dotenv # Install development dependencies npm install --save-dev mocha chai chai-http supertest nyc
describe() 블록을 사용한 그룹 관련 테스트
예상되는 동작을 명확하게 설명하는 설명이 포함된 테스트 이름을 사용하세요
각 테스트에서는 AAA(Arrange-Act-Assert) 패턴을 따릅니다
테스트를 원자적이고 독립적으로 유지
소스 코드 구조를 반영하도록 테스트 파일 구성
예:
{ "scripts": { "test": "NODE_ENV=test mocha --timeout 10000 --exit", "test:coverage": "nyc npm test" } }
'before'는 모든 테스트 전에 한 번 실행되고 'beforeEach'는 각 개별 테스트 전에 실행되고 'afterEach'는 각 개별 테스트 후에 실행되며 'after'는 모든 테스트가 완료된 후 한 번 실행됩니다. 이는 테스트 데이터를 설정하고 정리하는 데 유용합니다.
테스트에서 async/await 또는 return promise를 사용할 수 있습니다. 테스트 함수 앞에 'async'를 추가하고 비동기 작업을 호출할 때 'await'를 사용하세요. 더 긴 작업을 위해서는 적절한 시간 초과를 설정해야 합니다.
위 내용은 Mocha와 Chai를 사용한 NodeJS 단위 테스트의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!