Inspired World

Mocha 로 하는 JavaScript Testing 본문

Node.js

Mocha 로 하는 JavaScript Testing

InspiredJW 2016.08.08 10:41

Mocha 로 하는 JavaScript Testing

JavaScript (Node.js) 개발을 하면서 빨리빨리 기능 개발하고 새로고침 F5 를 연타하며 확인하고 다시 코드 수정하고 그러는게 일반적인데요.

테스트를 작성하면 조금 더 견고한 개발을 할 수 있습니다.




그럼 지금부터 Mocha 랑 Chai 라는 라이브러리를 이용해서 JavaScript 간단한 테스트 코드를 작성해보겠습니다.

TDD (Test Driven Development - 테스트 주도 개발) 느낌으로 테스트 먼저 작성해보겠습니다.


테스트 환경 세팅하기

Node.js v6.3.1 입니다.

설치되어 있지 않다면 Node.js 여기에서 다운 받습니다.

설치 이후에 npm도 함께 설치됩니다.

Node.js Package Manager, Node.js 모듈을 명령어 한줄로 쉽게 바로 설치해서 사용할 수 있습니다.


Mocha 설치

sudo npm install -g mocha

글로벌로 Mocha를 설치해줍니다.

-g로 이렇게 글로벌하게 모듈을 설치하게 되면 터미널창 어디에서든 바로 mocha 명령어를 사용할 수 있습니다.


프로젝트 폴더 생성

프로젝트 폴더를 하나 만들고 그 안에서 작업합니다.

작업을 시작하기 전에 필요한 모듈인 Chai를 설치합니다.

npm install chai

명령어를 실행하는 디렉토리는 프로젝트 폴더입니다.

명령어 실행후에는 프로젝트 폴더 안에 node_modules 폴더가 하나 생성되어야 합니다.

Chai 에서 공식 문서를 보실 수 있습니다.


먼저 구현할 기본 Function

// foobar.js
'use strict';

exports.foo = (a, b) => {};

exports.bar = (callback) => {};

프로젝트 폴더 안에 foobar.js를 위와 같이 작성합니다.

foo 함수에서는 곱셈을 해서 리턴 하는 함수를 구현할꺼고
bar 함수에서는 비동기로 JSON 오브젝트를 리턴하는 함수를 구현할 것입니다.


이에 맞춰서 테스트를 작성해보자면

테스트 코드

// test/fooTest.js
'use strict';

let chai = require('chai');
let should = chai.should();
let foo = require('../foobar').foo;

describe('Function Foo', () => {
  describe('with two number params', () => {
    it('should return product', () => {
      let result = foo(3, 4);
      result.should.be.a('number');
      result.should.equal(12);
    });
  });
});

test 폴더를 하나 만들고 그 안에 fooTest.js라는 파일을 위와 같이 생성합니다.


터미널 창에서 프로젝트 디렉토리에서 명령어를 입력합니다.

mocha

mocha는 명령어가 실행된 디렉토리에 있는 test폴더에 있는 모든 테스트 파일 또는 디렉토리에 있는 test.js를 찾아서 테스트를 실행합니다.

방금 작성한 테스트는 test/fooTest.js 이므로 실행됩니다.


결과는 실패...



이제 테스트가 무사히 통과될 수 있도록

Foo 함수를 구현합니다.


Foo 함수

'use strict';

exports.foo = (a, b) => {
    return a * b;
};

exports.bar = (callback) => {};

그럼 이제 다시 함수를 실행해볼까요?

mocha




첫번째 param과 두번째 param이 둘다 숫자가 맞는지, 아니라면 false가 return되도록 구현하는 방향으로 해볼까요?

먼저 테스트를 추가합니다.

// test/fooTest.js
'use strict';

let chai = require('chai');
let should = chai.should();
let foo = require('../foobar').foo;

describe('Function Foo', () => {
  describe('with two number params', () => {
    it('should return product', () => {
      let result = foo(3, 4);
      result.should.be.a('number');
      result.should.equal(12);
    });
  });

  describe('with non-number params', () => {
      it('should return false', () => {
        let result = foo(3, null);
        result.should.be.false;
    });
  });
});

mocha 명령어로 테스트를 실행해보면 새로 추가한 테스트는 실패합니다.

저희는 false 값을 기대하는데 결과가 0이라고 하죠?


그럼 테스트가 통과하도록 foo 함수를 수정해봅시다.

exports.foo = (a, b) => {
  if (typeof a !== 'number' || typeof b !== 'number') {
    return false;
  }

  return a * b;
};

mocha 명령어로 테스트를 다시 실행해보면 추가한 테스트는 통과합니다.


이런 식으로 각각의 함수를 구현하고 여러가지 경우의 수와 예상 결과를 테스트로 작성해서

여러가지 input에 따른 올바른 결과값이 나오는지, edge case (최소/최대 값, 곱하기 0 등), 타입 체크 등이 정상적으로 되는지 확인해볼 수 있습니다.




Bar 함수

그럼 이제 bar 함수 테스트를 먼저 작성해보겠습니다.

이 함수는 비동기 함수이기 때문에 함수가 끝나는 시점에 done을 호출해서 테스트가 동작하도록 합니다.

// test/barTest.js
'use strict';

let chai = require('chai');
let should = chai.should();
let bar = require('../foobar').bar;

describe('Function Bar', () => {
  it('should return product', (done) => {
    bar((result) => {
      result.should.be.a('object');
      let keys = Object.keys(result);
      keys.should.have.lengthOf(2);
      result.value1.should.equal(123);
      result.value2.should.equal('abc');
      done();
    });
  });
});

테스트를 실행하면 다음과 같이 Timeout 에러가 납니다.


같은 test 폴더에 있던 아까 작성한 테스트 결과도 함께 나오죠?

이 테스트 결과만 보고 싶다면

mocha test/barTest

하면 됩니다.


그럼 이제 bar 함수를 구현해봅시다.

1초 정도 걸리는 비동기 함수를 setTimeout을 이용해 시뮬레이션 합니다.

exports.bar = (callback) => {
  setTimeout(() => {
    callback({
      value1: 123,
      value2: 'abc'
    });
  }, 1000);
};

이제 테스트를 다시 실행하면

모든 테스트가 통과한 모습이 나옵니다.




테스트를 작성해야 하는 이유

아주 간단한 몇 분짜리 개발이라면 모를까 JavaScript 어플리케이션이 복잡하고 코드베이스가 점점 커질수록 그렇게 테스트하기에는

너무 코드가 많고 점점 추적할 수 없을정도로 버그 및 잠재적 버그가 많아지게 됩니다.

더군다나 지금은 나름 그럴저럭 돌아가는 코드인데 선뜻 리팩토링이라던가 신기능을 추가하면 되던 것도 안되는 불상사가 생길까봐 겁이 나서 건드리지도 못하게 됩니다.

테스트 코드를 씀으로써 자신의 코드의 상태에 대한 확신도 가지고 신기능 추가나 리팩토링 시에도 기존의 기능이 잘 돌아간다는 확신을 가질 수 있습니다.

더 나아가서는 자동화된 테스트 코드를 가짐으로써 Continuous Integration을 구축할 수 있습니다.

Master branch에 한 개발자가 새로운 코드를 push했을때 자동으로 테스트 코드가 돌아가고 기존의 기능을 망가뜨리지 않는지 확인합니다. 

테스트 통과시에는 실제 운영서버에 자동으로 배포를 하는 등의 응용도 가능해집니다.


Mocha 로 하는 API Testing 에 이어지는 내용이 있어요 확인해보세요.


저작자 표시 비영리 변경 금지
신고
0 Comments
댓글쓰기 폼