웹 애플리케이션 개발에서 테스트는 필수적인 과정입니다. 테스트는 코드의 신뢰성을 확보하고, 버그를 조기에 발견하며, 기능이 의도한 대로 동작하는지를 검증하는 데 중요한 역할을 합니다. 특히 Express.js와 같은 서버측 애플리케이션 개발에서는 Mocha와 Chai와 같은 도구를 통해 단위 테스트 및 통합 테스트를 쉽게 수행할 수 있습니다. 본 강좌에서는 이러한 도구들을 활용하여 Express 애플리케이션의 테스트를 작성하는 방법에 대해 설명합니다.
1. Mocha와 Chai 소개
Mocha는 Node.js와 브라우저에서 JavaScript 테스트를 수행하기 위한 유연한 테스트 프레임워크입니다. 비동기 테스트 실행을 지원하며, 다양한 보고서(output) 형식을 제공하여 테스트 결과를 쉽게 확인할 수 있습니다. Chai는 Mocha와 함께 사용할 수 있는 assertion 라이브러리로, 테스트에서 기대하는 결과를 검증하는 다양한 문법을 제공합니다. 이 두 도구는 함께 사용될 때 서로의 장점을 살려주며, 효율적인 테스트 환경을 제공합니다.
2. Express 애플리케이션 세팅하기
먼저 Express 애플리케이션을 만들기 위해 기본적인 환경을 설정해 보겠습니다. 다음은 Express 서버를 설정하는 예제 코드입니다.
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.json());
// 기본 라우트
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
3. Mocha 및 Chai 설치하기
프로젝트에 Mocha와 Chai를 추가하기 위해 다음의 명령어를 사용하여 설치합니다.
npm install --save-dev mocha chai
설치가 완료되면, package.json
파일을 열어 scripts
섹션에 Mocha를 실행할 수 있는 명령어를 추가합니다.
"scripts": {
"test": "mocha"
}
4. 단위 테스트 작성하기
이제 단위 테스트를 작성해보겠습니다. 단위 테스트는 개별적인 함수나 모듈을 독립적으로 검증하는 테스트입니다. 예를 들어, 위에서 작성한 Express 앱의 라우트 핸들러를 테스트 해보겠습니다.
const chai = require('chai');
const chaiHttp = require('chai-http');
const app = require('../app'); // 여러분의 Express 앱을 불러옵니다.
const should = chai.should();
chai.use(chaiHttp);
describe('GET /', () => {
it('기본 페이지를 요청할 때 200 상태코드와 응답을 확인합니다', (done) => {
chai.request(app)
.get('/')
.end((err, res) => {
res.should.have.status(200);
res.text.should.be.eql('Hello World!');
done();
});
});
});
위의 코드에서 chai-http
미들웨어를 사용하여 HTTP 요청을 테스트하는 방법을 볼 수 있습니다. describe
와 it
메소드는 Mocha의 구조로, 각 테스트의 기능과 유닛을 명명합니다.
5. 통합 테스트 작성하기
통합 테스트는 여러 모듈이나 서브시스템이 함께 잘 작동하는지를 검증하는 테스트입니다. 아래는 Express 애플리케이션의 CRUD(Create, Read, Update, Delete) 기능을 테스트하는 간단한 예제입니다.
const mongoose = require('mongoose');
const { app, closeDatabase, clearDatabase } = require('../app');
const chai = require('chai');
const chaiHttp = require('chai-http');
const UserModel = require('../models/User'); // 사용자 모델을 불러옵니다.
chai.use(chaiHttp);
afterEach(async () => {
await clearDatabase(); // 각 테스트 후 DB를 초기화합니다.
});
after(async () => {
await closeDatabase(); // 모든 테스트 완료 후 DB 연결 종료
});
describe('Users API', () => {
it('사용자를 생성합니다', (done) => {
const user = {
name: 'John Doe',
email: 'john@example.com'
};
chai.request(app)
.post('/users')
.send(user)
.end((err, res) => {
res.should.have.status(201);
res.body.should.have.property('name').eql('John Doe');
done();
});
});
it('모든 사용자를 조회합니다', (done) => {
chai.request(app)
.get('/users')
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a('array');
done();
});
});
});
6. Mocking과 Stubbing을 통한 테스트 개선하기
테스트를 더욱 효과적으로 만들기 위해, Mocking과 Stubbing 기법을 사용할 수 있습니다. 이는 외부 종속성을 제거하고, 테스트의 신뢰성을 높이는데 도움이 됩니다. Sinon.js 라이브러리를 사용하여 구현할 수 있습니다.
const sinon = require('sinon');
const UserService = require('../services/UserService');
describe('UserService', () => {
it('사용자가 없을 경우 빈 배열을 반환한다', () => {
const userService = sinon.stub(UserService, "getAllUsers").returns([]);
const result = userService();
result.should.be.a('array').that.is.empty;
userService.restore(); // 스텁 복원
});
});
7. 테스트 실행하기
모든 테스트를 작성하였다면, 다음 커맨드를 통해 테스트를 실행합니다.
npm test
성공적으로 테스트가 통과하면, 여러분의 코드는 정상적으로 작동하는 것입니다. 이를 통해 코드 변경 시에도 애플리케이션의 안정성을 유지할 수 있습니다.
8. 테스트 커버리지 확인하기
테스트 커버리지는 테스트가 얼마나 많은 코드 라인을 실행하는지를 측정하는 지표입니다. Istanbul과 같은 도구를 사용하여 커버리지를 확인할 수 있습니다. 커버리지 레포트는 코드의 미비한 부분을 찾아내는 데 유용합니다.
npm install --save-dev nyc
테스트 명령어를 업데이트하여 커버리지 리포트를 생성할 수 있도록 합니다.
"scripts": {
"test": "nyc mocha"
}
이제 다음 명령어로 커버리지 리포트를 확인할 수 있습니다.
npm test
9. CI/CD와 자동화
프로젝트에 CI/CD(지속적 통합 및 지속적 배포)를 적용하여 테스트를 자동화하는 것이 좋습니다. GitHub Actions, Travis CI, CircleCI 등과 같은 도구를 활용하여, 코드 변경 시 자동으로 테스트를 실행하고, 결과를 확인할 수 있습니다. 이는 팀의 협업을 더욱 원활하게 하고, 지속적인 코드 품질 향상에 기여합니다.
10. 마무리
이번 강좌에서는 Express 백엔드 서버 개발에 있어 Mocha와 Chai를 활용한 단위 테스트 및 통합 테스트에 대해 알아보았습니다. 테스트는 애플리케이션의 신뢰성을 높이고 유지보수를 쉬워지게 만들어줍니다. 코드를 작성할 때 테스트를 미리 고려하는 습관을 들이면, 개발 과정의 상당 부분에서 품질을 보장할 수 있습니다. 앞으로의 개발에서도 테스트를 적극 활용하시길 바랍니다.