Node.js에서 테스트 코드를 작성하는 것은 코드의 정확성, 안정성, 유지보수성을 보장하는 데 중요한 역할을 합니다. 이를 통해 개발자는 코드가 예상대로 동작하는지 확인하고, 코드 변경이 기존 기능에 영향을 미치지 않도록 할 수 있습니다. 테스트는 소프트웨어 개발의 필수적인 부분이며, 다양한 테스트 프레임워크와 라이브러리를 사용하여 효율적으로 작성할 수 있습니다. 이번 포스팅에서는 Mocha와 Chai와 supertest를 이용한 테스트 코드를 작성하는 방법을 알아보겠습니다.
Node.js에서 테스트(Test)란?
Node.js에서 테스트는 작성된 코드가 예상대로 작동하는지 검증하기 위해 수행하는 프로세스입니다.
테스트는 코드의 품질을 보장하고, 코드 변경이 기존 기능에 부정적인 영향을 미치지 않도록 합니다.
Node.js에서는 다양한 테스트 프레임워크와 라이브러리를 사용하여 테스트를 작성하고 실행할 수 있습니다.

1. 테스트의 중요성
- 버그 발견: 코드 작성 초기 단계에서 버그를 발견하여 수정할 수 있습니다.
- 코드 품질 향상: 테스트를 통해 코드의 안정성과 신뢰성을 높일 수 있습니다.
- 자동화: 지속적인 통합(CI, Continuous Integration) 환경에서 테스트를 자동으로 실행하여 코드 변경이 문제를 일으키지 않는지 확인할 수 있습니다.
- 문서화: 테스트는 코드의 기능을 설명하는 데 도움이 되며, 다른 개발자들이 코드를 이해하는 데 유용합니다.
2. 테스트의 종류
Node.js에서 일반적으로 사용되는 테스트의 종류는 다음과 같습니다:
- 단위 테스트(Unit Test): 개별 함수나 모듈을 테스트하여 예상되는 결과를 확인합니다.
- 통합 테스트(Integration Test): 여러 모듈이 함께 작동하는지 확인합니다.
- 엔드 투 엔드 테스트(End-to-End Test): 애플리케이션의 전체 흐름을 테스트하여 사용자 시나리오를 검증합니다.
- 성능 테스트(Performance Test): 애플리케이션의 성능과 반응 속도를 테스트합니다.
- 회귀 테스트(Regression Test): 새로운 코드 변경이 기존 기능에 영향을 미치지 않는지 확인합니다.
Test 모듈
Node.js 프로젝트에서 사용할 수 있는 다양한 테스트 모듈들이 있으며, 각 모듈은 고유한 특징과 장점을 가지고 있습니다. 주요 테스트 모듈과 그 특징을 살펴보겠습니다.
그리고 소개해준 아래 모듈들 중 이번 포스팅에서는 Mocha와 Chai를 사용해볼 예정입니다.
1. Mocha
Mocha는 Node.js 및 브라우저를 위한 기능이 풍부한 테스트 프레임워크입니다.
- 특징:
- 비동기 테스트 지원
- 다양한 리포터(테스트 결과 출력 형식)를 제공
- BDD(Behavior Driven Development)와 TDD(Test Driven Development) 스타일 모두 지원
- 플러그인과 assertion 라이브러리를 쉽게 통합 가능 (예: Chai)
2. Jest
Jest는 Facebook에서 개발한 JavaScript 테스트 프레임워크로, 특히 React 프로젝트에서 널리 사용됩니다.
- 특징:
- 기본적으로 내장된 assertion 라이브러리와 모의(Mock) 기능
- 코드 커버리지 보고서 자동 생성
- 스냅샷 테스트 지원 (UI 테스트에 유용)
- 빠르고 병렬로 테스트 실행
- 설정이 간단하고 바로 사용 가능
3. Chai
Chai는 BDD/TDD 스타일의 assertion 라이브러리로, Mocha와 같은 테스트 프레임워크와 함께 사용됩니다.
- 특징:
- 세 가지 주요 assertion 스타일 지원: Should, Expect, Assert
- 플러그인 확장 가능
- 다양한 내장 assertion 메서드 제공
4. Jasmine
Jasmine은 행동 기반 테스트 프레임워크로, JavaScript 테스트를 위한 가장 오래된 프레임워크 중 하나입니다.
- 특징:
- 종속성 없이 독립적으로 사용 가능
- BDD 스타일의 테스트 작성 가능
- 내장된 스파이(Spy)와 스텁(Stub) 기능
- 브라우저와 Node.js 환경 모두에서 사용 가능
5. Ava
Ava는 최신 JavaScript 기능을 활용한 테스트 프레임워크로, 간결하고 빠른 테스트 실행을 목표로 합니다.
- 특징:
- 테스트의 병렬 실행을 기본으로 하여 빠른 테스트 속도 제공
- 간단하고 간결한 문법
- 비동기 테스트 지원을 위한 Promises와 async/await 사용
- 기본적으로 설치되는 코드 커버리지 지원
Mocha 소개
Mocha란?
Mocha는 Node.js 및 브라우저 환경에서 사용 가능한 기능이 풍부한 자바스크립트 테스트 프레임워크입니다.
테스트 작성과 실행에 필요한 다양한 기능을 제공하여, 개발자가 코드의 품질을 보장할 수 있도록 돕습니다.
Mocha 공식 페이지 (with Document)
주요 특징
- 비동기 테스트 지원:
- Mocha는 비동기 코드 테스트를 쉽게 작성할 수 있도록 도와줍니다. 콜백, 프로미스, async/await을 모두 지원합니다.
- BDD와 TDD 스타일 지원:
- Mocha는 BDD(Behavior Driven Development)와 TDD(Test Driven Development) 스타일의 테스트 작성 방식을 모두 지원합니다.
describe
,context
,it
등의 BDD 스타일과suite
,test
등의 TDD 스타일을 사용할 수 있습니다.
- Mocha는 BDD(Behavior Driven Development)와 TDD(Test Driven Development) 스타일의 테스트 작성 방식을 모두 지원합니다.
- 다양한 리포터:
- Mocha는 테스트 결과를 다양한 형식으로 출력할 수 있는 리포터를 제공합니다. 기본적으로 콘솔에서 읽기 쉽게 출력하는 ‘spec’ 리포터 외에도, JSON, HTML 등의 형식을 지원하는 여러 리포터가 있습니다.
- 확장성:
- Mocha는 플러그인과 미들웨어를 통해 확장할 수 있습니다. 다양한 assertion 라이브러리와의 통합이 용이하며, 필요에 따라 커스텀 리포터나 미들웨어를 작성할 수 있습니다.
- 설정 파일을 통한 구성:
- Mocha는
.mocharc.json
,.mocharc.yml
등 다양한 형식의 설정 파일을 통해 동작 방식을 쉽게 구성할 수 있습니다.
- Mocha는
주요 Class 소개
1. Mocha
Mocha
클래스는 Mocha의 핵심 클래스입니다.
이 클래스는 Mocha 인스턴스를 생성하고, 테스트 Suite
와 테스트 케이스를 관리하며, 테스트를 실행하는 데 사용됩니다.
예)
const Mocha = require('mocha'); const mocha = new Mocha(); mocha.addFile('test/test.js'); mocha.run();
2. Runner
Runner
클래스는 테스트 실행을 관리합니다.
테스트 케이스를 순차적으로 실행하고, 각 테스트의 결과를 처리합니다.
Runner
는 내부적으로 사용되며, 테스트 결과를 리포터에 전달합니다.
run()
을 통해 Test를 실행하며, on(event, listener)
를 통해 이벤트 리스너를 등록합니다. 이벤트로는 pass
, fail
, end
가 있습니다.
const runner = mocha.run(); runner.on('pass', (test) => { console.log('Test passed:', test.fullTitle()); }); runner.on('fail', (test, err) => { console.log('Test failed:', test.fullTitle(), err); });
3. Suite
Suite
클래스는 테스트 스위트를 나타냅니다.
Suite
는 테스트 케이스를 그룹화하고, 각 스위트의 설정과 클린업 작업을 정의할 수 있습니다.
주요 Method 및 Property:
addTest(test)
: 테스트 케이스를 추가합니다.beforeAll(fn)
: 모든 테스트 케이스가 실행되기 전에 한 번 실행할 함수를 정의합니다.afterAll(fn)
: 모든 테스트 케이스가 실행된 후에 한 번 실행할 함수를 정의합니다.beforeEach(fn)
: 각 테스트 케이스가 실행되기 전에 실행할 함수를 정의합니다.afterEach(fn)
: 각 테스트 케이스가 실행된 후에 실행할 함수를 정의합니다.
예)
const suite = Mocha.Suite.create(mocha.suite, 'My Suite'); suite.beforeAll(() => { console.log('Before all tests'); }); suite.afterAll(() => { console.log('After all tests'); }); suite.beforeEach(() => { console.log('Before each test'); }); suite.afterEach(() => { console.log('After each test'); });
4. Test
Test
클래스는 개별 테스트 케이스를 나타냅니다.
각 테스트 케이스는 it
함수로 정의되며, 테스트 실행 로직과 예상 결과를 포함합니다.
주요 메서드 및 프로퍼티:
title
: 테스트 케이스의 제목을 나타냅니다.fn
: 테스트 케이스로 실행할 함수입니다.run(fn)
: 테스트 케이스를 실행합니다.
const test = new Mocha.Test('should return true', function() { assert.equal(true, true); }); suite.addTest(test);
5. Context
Context
클래스는 테스트 실행 시 컨텍스트를 제공합니다.
this
키워드를 통해 접근할 수 있으며, 각 테스트 케이스나 훅에서 공유 데이터를 저장하는 데 사용할 수 있습니다.
describe('Test Suite', function() { beforeEach(function() { this.someValue = 42; }); it('should have someValue set to 42', function() { assert.equal(this.someValue, 42); }); });
6. Hook
Hook
클래스는 각 테스트 스위트의 설정과 클린업 작업을 정의하는 훅을 나타냅니다.
before
, after
, beforeEach
, afterEach
와 같은 훅이 있습니다.
const hook = new Mocha.Hook('beforeEach hook', function() { console.log('Running before each test'); }); suite.addHook(hook);
Chai 소개
Chai란?
Chai는 BDD/TDD 스타일의 assertion 라이브러리입니다.
Mocha와 같은 테스트 프레임워크와 함께 사용되어, 테스트 코드에서 예상 결과를 검증하는 데 사용됩니다.
주요 특징
- 다양한 assertion 스타일:
- Chai는 세 가지 주요 assertion 스타일을 지원합니다
: Should, Expect, Assert. 이를 통해 다양한 방식으로 테스트 결과를 검증할 수 있습니다.
- Chai는 세 가지 주요 assertion 스타일을 지원합니다
- 확장성:
- Chai는 플러그인을 통해 기능을 확장할 수 있습니다.
- Chai-as-promised와 같은 플러그인을 사용하면 비동기 코드 테스트를 더욱 쉽게 작성할 수 있습니다.
- 유연성:
- Chai는 다양한 테스트 시나리오에 맞게 유연하게 사용할 수 있습니다.
- BDD와 TDD 스타일을 모두 지원하여 개발자의 선호에 따라 선택할 수 있습니다.
주요 Class 소개
1. expect
스타일
expect
스타일은 함수형 assertion 스타일로, 간결하고 읽기 쉬운 문법을 제공합니다.
주요 메서드
to.equal(value)
: 기대한 값과 실제 값이 일치하는지 확인합니다.to.be.a(type)
: 값의 타입을 확인합니다.to.have.property(name, [value])
: 객체가 특정 속성을 가지고 있는지, 그리고 그 값이 일치하는지 확인합니다.to.include(value)
: 배열이나 문자열에 특정 값이 포함되어 있는지 확인합니다.to.be.true
/to.be.false
: 값이 참인지 또는 거짓인지 확인합니다.to.be.null
/to.be.undefined
: 값이 null 또는 undefined인지 확인합니다.
const { expect } = require('chai'); expect(2 + 2).to.equal(4); expect('foo').to.be.a('string'); expect([1, 2, 3]).to.include(2); expect({ foo: 'bar' }).to.have.property('foo'); expect(true).to.be.true; expect(null).to.be.null;
2. should
스타일
should
스타일은 BDD 스타일의 assertion을 제공합니다.
객체의 프로토타입을 확장하여 자연어와 같은 문법을 사용합니다.
주요 메서드
should.equal(value)
: 기대한 값과 실제 값이 일치하는지 확인합니다.should.be.a(type)
: 값의 타입을 확인합니다.should.have.property(name, [value])
: 객체가 특정 속성을 가지고 있는지, 그리고 그 값이 일치하는지 확인합니다.should.include(value)
: 배열이나 문자열에 특정 값이 포함되어 있는지 확인합니다.should.be.true
/should.be.false
: 값이 참인지 또는 거짓인지 확인합니다.should.be.null
/should.be.undefined
: 값이 null 또는 undefined인지 확인합니다.
const chai = require('chai'); const should = chai.should(); (2 + 2).should.equal(4); 'foo'.should.be.a('string'); [1, 2, 3].should.include(2); ({ foo: 'bar' }).should.have.property('foo'); true.should.be.true; null.should.be.null;
3. assert
스타일
assert
스타일은 TDD 스타일의 assertion을 제공합니다.
함수 기반 assertion 을 사용하여 간결하게 assertion 을 작성할 수 있습니다.
주요 메서드
assert.equal(actual, expected)
: 실제 값과 기대한 값이 일치하는지 확인합니다.assert.typeOf(value, type)
: 값의 타입을 확인합니다.assert.property(object, property)
: 객체가 특정 속성을 가지고 있는지 확인합니다.assert.include(array, value)
: 배열이나 문자열에 특정 값이 포함되어 있는지 확인합니다.assert.isTrue(value)
: 값이 참인지 확인합니다.assert.isFalse(value)
: 값이 거짓인지 확인합니다.assert.isNull(value)
: 값이 null인지 확인합니다.assert.isUndefined(value)
: 값이 undefined인지 확인합니다.
const assert = require('chai').assert; assert.equal(2 + 2, 4); assert.typeOf('foo', 'string'); assert.include([1, 2, 3], 2); assert.property({ foo: 'bar' }, 'foo'); assert.isTrue(true); assert.isNull(null);
supertest
소개
supertest
는 HTTP assertions을 위한 라이브러리로, Node.js 환경에서 Express와 같은 웹 애플리케이션을 테스트하는 데 널리 사용됩니다.
supertest
를 사용하면 HTTP 요청을 시뮬레이션하고 응답을 검증할 수 있습니다.
주요 기능
- HTTP 요청 시뮬레이션: GET, POST, PUT, DELETE 등 다양한 HTTP 요청을 보낼 수 있습니다.
- 응답 검증: 상태 코드, 헤더, 본문 등을 검증할 수 있습니다.
- Promise 기반: 비동기 테스트를 쉽게 작성할 수 있도록 Promise를 지원합니다.
기본 사용법
설치
$ npm install supertest --save-dev
주요 Class 및 method
1. request(app)
테스트할 애플리케이션을 설정합니다. app
은 Express 애플리케이션 인스턴스입니다.
import request from "supertest"; import app from "../src/app"; request(app) .get('/') .expect(200);
2. HTTP 메소드
supertest
는 HTTP 메소드(GET, POST, PUT, DELETE 등)에 해당하는 메소드를 제공합니다.
각 메소드는 URL 경로를 인수로 받아 해당 경로에 요청을 보냅니다.
request(app) .get('/path') .expect(200); // GET 요청 request(app) .post('/path') .send({ key: 'value' }) .expect(201); // POST 요청 request(app) .put('/path') .send({ key: 'value' }) .expect(200); // PUT 요청 request(app) .delete('/path') .expect(204); // DELETE 요청
3. .expect(status[, body])
응답의 상태 코드와 선택적으로 본문을 검증합니다.
상태 코드만 검증할 때는 첫 번째 인수로 상태 코드를 전달하고, 본문을 함께 검증할 때는 두 번째 인수로 본문을 전달합니다.
request(app) .get('/path') .expect(200); request(app) .post('/path') .send({ key: 'value' }) .expect(201, { message: 'Created', key: 'value' });
4. .send(data)
POST나 PUT 요청의 본문 데이터를 보낼 때 사용합니다.
data
는 JSON 객체일 수 있습니다.
request(app) .post('/path') .send({ key: 'value' }) .expect(201);
5. .set(field, value)
요청 헤더를 설정합니다. field
는 헤더 이름, value
는 헤더 값입니다.
request(app) .get('/path') .set('Authorization', 'Bearer token') .expect(200);
6. .query(params)
쿼리 문자열을 설정합니다. params
는 쿼리 문자열에 추가할 키-값 쌍의 객체입니다.
request(app) .get('/search') .query({ q: 'term' }) .expect(200);
7. .end(callback)
요청을 끝내고 콜백 함수를 실행합니다. 콜백 함수는 err
와 res
인수를 받습니다.
이를 통해 요청이 완료된 후 추가적인 검증을 수행할 수 있습니다.
request(app) .get('/path') .expect(200) .end((err, res) => { if (err) throw err; console.log(res.body); });
8. .auth(user, pass)
기본 인증을 설정합니다. user
는 사용자 이름, pass
는 비밀번호입니다.
request(app) .get('/path') .auth('username', 'password') .expect(200);

전체 예제 프로젝트
아래 git hub repository에 전체 예제 코드를 업로드해 놓았습니다.
devitworld nodejs tutorial repository
- https://github.com/jh4843/devitworld-nodejs-basic/09_test_mocha