본문으로 바로가기

API를 만들 때는 테스트 주도 개발(TDD) 방식으로 이용하는 것이 좋다. 소스 코드를 개발하는 시간보다 유지보수하는 시간이 더 오래 걸리기 때문에 TDD로 개발하면 유지 보수하는 시간을 줄여준다. 물론 처음 개발할 때는 시간이 조금 더 걸리긴 한다.

 

* 너무 당연한 말이지만 테스트에 필요한 모듈들은 모두 -D (dev dependencies)로 설치하자. 

 

Node에서 TDD를 사용하기 위해서는 mocha, should, superTest가 주로 이용된다.

유닛 테스트에 한해 Jest로 대통합되는 분위기네요 이제... 

React는 react testing libary를 쓰고, e2e에는 Enzyme을 쓰는 등 다른 라이브러리도 많이 나오는 편

 

 

☕ mocha

 

mocha는 테스트 코드를 돌려주는 테스트 러너이다. 문서가 그렇게 길지 않으니 한 번 다 읽어보자.

 

 

Mocha - the fun, simple, flexible JavaScript test framework

Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct te

mochajs.org

 

모카는 크게 두 파트로 나뉜다. 테스트 수트와 테스트 케이스.

테스트 수트는 테스트 환경으로, describe()로 구현한다. 테스크 케이스는 실제 테스트를 말하며 it()으로 구현한다.

 

설치

npm i -g mocha
npm i -D mocha

 

간단하게 utils.js를 만들고 utils.spec.js에서 테스트해보자. 테스트를 실행하는 sj파일은 spec.js 확장자가 붙는다.

const capitalize = (str) => {
  return str.charAt(0).toUpperCase() + str.slice(1);
};

module.exports = {
  capitalize: capitalize,
};
// spec.js은 js 테스트 코드를 말합니다.
// specification의 약자입니다.

// 작성한 utils 검증을 위해 import
const utils = require("./utlis");

// node 내장 모듈 assert
const assert = require("assert");

describe("utils.js를 테스트합니다.", () => {
  it("문자열의 첫번째 문자를 대문자화", () => {
    const result = utils.capitalize("hello");
    assert.equal(result, "Hello");
  });
});

 

이후 테스트를 하기 위해서는 package.json의 scripts를 설정한다. npm init를 하면 scripts에 자동으로 있던 test 명령어를 드디어 사용하게 된다.

  "scripts": {
    //"test": "echo \"Error: no test specified\" && exit 1",
    // test를 반복해서 실행하는 것이 귀찮다면 nodemon --exec mocha index.spec.js를 입력
    "test": "mocha utils.spec.js",
    "start": "nodemon --exec node index --delay 2"
  },

 

npm run test를 돌리면 다음과 같을 결과를 출력한다. 왼쪽은 실패, 오른쪽은 성공

 

 

 

✔ should

 

express에서는 테스트에서 assert보다 다른 서드 파티 모듈을 사용할 것을 권장하고 있다. 테스트코드에서 검증 라이브러리로 주로 사용되는 것이 should이다.

 

 

shouldjs/should.js

BDD style assertions for node.js -- test framework agnostic - shouldjs/should.js

github.com

 

설치

 

npm i -D should

 

위의 utils.spec.js에서 assert를 should로 교체했습니다. 

// spec.js은 js 테스트 코드를 말합니다.
// specification의 약자입니다.

const utils = require("./utlis");
const should = require("should");

describe("utils.js를 테스트합니다.", () => {
  it("문자열의 첫번째 문자를 대문자화", () => {
    const result = utils.capitalize("hello");
    result.should.be.equal("Hello");
  });
});

 

 

🦸 superTest

 

visionmedia/supertest

🕷Super-agent driven library for testing node.js HTTP servers using a fluent API. - visionmedia/supertest

github.com

 

단위 테스트 : 함수의 기능 테스트

통합 테스트 : API 기능 테스트

 

지금까지 작성한 건 대문자화를 하는 함수를 테스트한 것이므로 단위 테스트이다. superTest는 익스프레스 통합 테스트용 모듈이다. 내부적으로 익스프레스 서버를 구동시켜 시나리오대로 실제 요청을 보낸 뒤 결과를 검증한다.

 

위 github에서 제공해준 예시를 살펴보자

 

const request = require('supertest');
const express = require('express');

const app = express();

app.get('/user', function(req, res) {
  res.status(200).json({ name: 'john' });
});

request(app)
  .get('/user')
  .expect('Content-Type', /json/)
  .expect('Content-Length', '15')
  .expect(200)
  .end(function(err, res) {
    if (err) throw err;
  });

 

request를 보면, /user GET을 날리면 Content-Type이 json이고 length 15, 상태 코드는 200번을 받기를 기대(expect)한다. 만약 에러가 있다면 에러를 던지는 걸로 마무리(end) 한다.

 

간단하다. 바로 사용해보자.

 

설치

npm i -D supertest

 

활용

 

통합 테스트하고자 하는 파일의 spec.js를 만들어 테스트를 돌리면됩니다. 여기서 주의해야 할 것이, 실제로 express 서버를 가동시키는 것이기 때문에 nodemon으로 이미 서버를 돌리고 있다면 꺼야 한다는 것입니다.

(왜 안되는지 계속 해보다가 오류창을 읽어보니 listen EADDRINUSE: address already in use :::3000라고 합니다... 하...)

 

// index.js

const express = require("express");
const logger = require("morgan");

const app = express();

... 중략

app.listen(PORT, () => console.log(`http://localhost:${PORT}`));

module.exports = app;

 

여기서 중요한 건 done()의 사용입니다.

Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

// index.spec.js

const app = require("./index");
const request = require("supertest");

describe("Get users를 불러옵니다.", () => {
  it("...", (done) => {
    request(app)
      .get("/users")
      .expect(200)
      .end((err, res) => {
        if (err) {
          return done(err);
        }
        console.log(res.body);
        done();
      });
  });
});

 

 

체크한대로 성공했습니다!


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체