Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

node.js TDD 프레임워크 : expresso

expresso는 JAVA의 JUnit같은 node.js에서 사용할 수 있는 TDD 프레임워크입니다.(웹프레임워크인 express와 이름은 비슷하지만 아주 다릅니다.) Vowsexpresso가 가장 유명한데 Vows는 BDD 프레임워크이기 때문에 expresso를 사용하기로 결정했습니다.

  • assert.eql()
  • assert.deepEqual()
  • assert.response()
  • assert.includes()
  • assert.type()
  • assert.isNull()
  • assert.isUndefined()
  • assert.isNotNull()
  • assert.isDefined()
  • assert.match()
  • assert.length()
expresso는 위와같은 assert문을 지원하고 있습니다. 일반적으로 필요한 assert는 대부분 지원하고 있는듯 합니다. 설치는 npm을 이용해서 npm install expresso으로 간단하게 설치할 수 있습니다. 사용하는 법은 아래와 같습니다.


var obj = require('obj.js'),
    assert = require('assert');
    
module.exports = {
    'test method': function() {
        assert.equal('1', obj.mehtod());
    }
};

assert를 사용하기 위해서 해당 모듈을 불러온뒤에 module.exports에 JSON형식으로 테스트를 적어주면 됩니다. 키값이 되는 부분을 라벨처럼 사용하기 때문에 같은 이름을 사용하면 한개만 테스트하기 때문에 이름을 따로 적어주어야 합니다. 그리고 node.js에서는 외부에서 모듈의 메서드를 호출해서 사용하려면 module.exports로 정의되어야 하기 때문에 express서버 같은 경우 app = express.createServer();app = module.exports = express.createServer();로 수정해 주어야 합니다. 테스트를 위해서 소스의 수정이 있어야 하는 건 별로 좋은 생각은 아닌것 같지만 node.js에 환경에서는 어쩔수 없는 방법인듯 합니다.

expresso에서 특이한 부분은 assert.response()입니다. 이 assert메서드는 일반적인 유닛테스트에는 없는 메서드로 http요청에 대한 결과 테스트를 수행하는 테스트로 요청에 대한 설정을 한뒤 응답을 비교해 보는 것으로 테스트가 수행이 됩니다. 아무래도 node.js로 웹애플리케이션을 만드는 경우가 많고 그에 대한 테스트를 위해서 추가된 것으로 보입니다.


assert.response(app, {
    url: '/',
    method: 'GET',
    data: '{"q": "test"}',
}, {
    status: 200,
    headers: { 'Content-Type': 'application/json' },
    body: '{"response":"result"}',
});

response에 대한 테스트는 위와 같이 합니다. 첫번째 파라미터로 서버를 지정해 주고 두번째 파라미터에서 테스트할 요청에 대한 설정을 지정해 줍니다. 세번째 파라미터로 기대하는 응답의 결과를 적어주면 됩니다.(정확하게 보면 유닛테스트는 아닌듯 합니다.)

app.configure('test', function() {});

웹프레임워크인 express를 사용할 때 아래와 같이 test환경 설정을 따로 지정해 주었다면 테스트 상단에 process.env.NODE_ENV = 'test';를 추가하여 테스트환경을 강제할 수 있습니다. 또한 express를 사용할때 웹서버를 expresso가 자동으로 실행시켜주기 때문에 기존에 서버를 시작하는 부분은 아래와 같이 테스트로 시작되는 것이 아닐때만 시작되도록 해야 합니다.


if (!module.parent) {
    app.listen(3000);
}

테스트를 실행하려면 터미널에서 아래와 같은 명령어를 사용하면 됩니다.

expresso
expresso *.js
expresso {a,b}.test.js c.test.js

첫 명령어는 현재위치에서 test디렉토리 아래 있는 *.test.js를 모두 실행해 줍니다. test/*.test.js라는 관례를 따르지 않았을 때는 2번째나 3번째 라인처럼 파일을 지정해서 테스트를 수행할 수 있습니다. 테스트를 수행하면 아래와 같이 나타납니다.

expresso 테스트가 성공한 화면

위는 테스트가 모두 성공했을 때이고 아래는 실패한 테스트입니다.

expresso 테스트가 실패한 화면

녹색과 적색을 볼 수 있는건 좋지만 터미널의 한계때문인지 실패했을때의 결과를 보여주는 것이 별로 맘에 들지는 않습니다.  assert.respond()같은 경우는 기대값은 무엇인데 무슨 값을 얻었다는 식으로 보여주는데 다른 assert는 실패화면이 그다지 눈에 들어오지는 않는것 같습니다.(제가 test에 많이 익숙하지 않아서 그럴수도 있습니다.)

저는 간단한 용도로만 사용을 해서 아직 다양한 케이스의 필요까지는 못 느끼고 있기는 한데 JUnit처럼 fixture를 설정하는 부분은 아직 없는듯 합니다. 사용법에 대한 문서는 expresso 페이지에 잘 나와있고 예제코드를 참고하는 것도 꽤 도움이 됩니다. 소스수정할때 마다 node앱을 새로 실행하지 않아도 되기 때문에 생산성에는 꽤 좋은것 같습니다.

테스트해보다가 느낀건데 node.js가 테스트하기 좋은 형태는 아닌것 같습니다. 아직 역사가 짧아서 좀 더 연구되어야 하겠지만 간단한 메서드는 상관없지만 I/O가 필요한 경우는 모두 콜백으로 실행이 되기 때문에 테스트가 만만치 않습니다. 웹서버 -> 메서드 실행 > 디비 조회의 형식이 될 경우 디비조회의 콜백이 결과값을 처리하기 때문에 마지막 콜백은 따로 테스트 할 수 있지만 중간의 메서드는 테스트하기가 애매합니다. 메일링에서도 현재 테스트의 형태가 그리 깔끔한 형태는 아니라고 얘기되는데 이부분은 앞으로 좀더 개선되어야 할 것 같습니다.
2011/02/04 23:22 2011/02/04 23:22