should.js : node.js에서 사용할 수 있는 BDD 스타일의 Assertion 모듈
몇일 전에 mocha 테스트 프레임워크를 소개 한 관계로 mocha에서 사용할 수 있는 assetion 모듈인 should.js 를 정리해 봅니다. mocha 글에서도 썼듯이 mocha는 꼭 should.js를 써야하는 것은 아니지만 사용법도 깔끔하고 개인적으로 mocha와 should.js를 만든 TJ Holowaychuk에 대한 신뢰도 있기 때문에 should.js를 사용하고 있습니다.(이러다 LearnBoost 빠돌이 되겠;;;) assertion 모듈이라는 것이 간단한 메서드와 인터페이스만 파악하면 큰 내용은 없기 때문에 정리라고 하기 보다는 should.js 의 문서를 그대로 옮겨놓는 정도이지만 그래서 오히려 문서를 찬찬히 본적도 없기에 한번 찬찬히 보는 셈 치고 정리합니다.
should.js
should.js 는 node.js에서 사용할 수 있는 표현적이고 가독성있으며 테스트 프레임워크에 의존적이지 않은 단언문(assertion) 라이브러리입니다. 객체의 행동을 enumerable않은 단일 getter를 통해 Object를 prototype 확장해서 제공하고 있습니다.
그리고 사실 should.js는 node.js에서 제공하는 Assert 모듈 을 확장했기 때문에 assert 모듈과 동일합니다. 즉 should.equal(str, 'foo')는 assert.equal(str, 'foo')와 똑같이 동작하고 should.AssertionError는 assert.AssertionError와 같습니다. 그래서 node.js의 assert 모듈을 지원하는 어떤 테스트 프레임워크에서도 should.js를 사용할 수 있습니다.
should.js는 소스에서 사용해야 하므로 다음과 같이 로컬설치를 합니다.
$ npm install should
이후의 예제는 소스에서 var should = require('should');로 불러왔다는 가정하에 설명합니다.
should.js의 추가 메서드
앞에서 얘기했듯이 require('should')가 리턴한 객체는 require('assert')가 리턴한 객체를 확장한 것과 같고 assertion을 더 표현적이고 가독성 좋게 하는 추가적인 메서드들을 제공하고 있습니다.
exist (정적)
1 2 3 |
|
위 두 코드는 동일합니다. should.strictEqual(foo, bar)는 assert.strictEqual(foo, bar)와 동일합니다. 하지만 should는 Object를 prototype확장했기 때문에 2번라인처럼 작성할 수 있습니다. 이는 더 가독성있게 만들어 줍니다. 하지만 위에서 foo가 존재하지 않는 경우에는 foo is null or undefined이라는 오류가 발생할 것입니다. 객체나 프로퍼티의 존재를 알 수 없는 경우에는 이와 같이 사용할 수 없습니다. 객체나 프로퍼티의 존재 여부는 다음과 같이 exist 메서드로 확인할 수 있습니다.
1 2 3 4 5 6 |
|
다음과 같이 not을 사용해서 부정문으로 사용할 수도 있습니다.
1 2 3 4 |
|
이렇게 객체의 존재여부를 확인한 뒤에는 맘편히 객체에 should를 사용할 수 있습니다.
ok
assertion의 진실성(?)은 ok로 검사합니다. 이는 소스 내부에서 그냥 전달한 객체 obj로만 검사합니다. obj == true가 아니라 그냥 obj로 검사한다는 의미입니다.
1 2 3 4 5 6 7 |
|
true / false
true와 false는 다음과 같이 사용합니다. 이는 Assert === true나 Assert === false로 검사합니다.
1 2 3 4 5 |
|
arguments
arguments는 Arguments의 인스턴스인지를 검사합니다.
1 2 3 |
|
empty
empty는 객체의 length가 0인지 검사합니다.
1 2 3 |
|
eql
두 객체가 동등한지 검사합니다. 단순값은 ==로 검사하고 객체일 경우에는 내부 속성을 ===로 검사합니다.
1 2 |
|
equal
strict 하게 동등성을 비교합니다. 비교는 ===로 검사합니다.
1 2 3 4 5 |
|
within
숫자의 범위를 포함하는지 검사합니다.
1
|
|
a
객체의 typeof를 검사합니다.
1 2 |
|
instanceof
instanceof를 검사합니다.
1 2 |
|
above
주어진 값이 지정한 숫자 값보다 큰 지를 검사합니다.
1 2 |
|
below
주어진 값이 지정한 숫자 값보다 작은 지를 검사합니다. regexp.exec로 검사합니다.
1 2 |
|
match
정규표현식의 match 여부를 검사합니다.
1
|
|
length
length 프로퍼티가 존재하는지 검사하고 주어진 숫자값인지를 검사합니다. lengthOf는 length의 별칭입니다.
1 2 |
|
property
property에 첫 파라미터로 전달한 이름의 프로퍼티가 존재하는지 검사하고 두 번째 파라미터를 전달하면 해당 프로퍼티가 두 번재 파라미터 값인지 검사합니다.
1 2 3 4 |
|
ownProperty
prototype 속성이 아닌 객체 자체가 가진 속성이 존재하는지 검사합니다. 검사는 obj.hasOwnProperty(name)로 수행합니다.
1
|
|
status(code)
객체가 statusCode 프로퍼티를 가지고 있는지 검사하고 statusCode 프로퍼티가 code값인지를 검사합니다.
1
|
|
header(field[, value])
객체가 headers 프로퍼티가 존재하는지 검사하고 field로 지정한 프로퍼티가 존재하는지 검사합니다. value를 전달하면 field 프로퍼티가 value값인지 검사합니다.
1 2 3 |
|
json
Content-Type가 "application/json; charset=utf-8"인지 검사합니다.
1
|
|
html
Content-Type가 "text/html; charset=utf-8"인지 검사합니다.
1
|
|
include(obj)
전달한 obj가 indexOf()로 나타낼 수 있는지 검사합니다. 그래서 문자열과 배열이나 indexOf를 구현한 객체에서 사용할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 |
|
includeEql(obj)
배열에서 사용할 수 있으면 전달한 obj와 같은 객체가 있는지 검사합니다.
1 2 3 |
|
throw([message])
예외가 던져지는 지 검사합니다.
1 2 3 4 5 6 7 |
|
throw()에 message를 전달하면 예외 메시지가 message와 일치하는지 검사합니다. message에는 정규표현식을 사용할 수도 있습니다.
1 2 3 4 5 6 7 |
|
keys
전달한 키의 이름을 객체가 모두 가지고 있는지 검사합니다. 배열이나 파라미터로 전달할 수 있는데 객체에서 빠진 키가 있으면 실패합니다.
1 2 3 |
|
체이닝과 오류 메시지
앞의 예제에서 보았듯이 assertion은 체이닝으로 연결할 수 있습니다.
1
|
|
이는 다음 코드와 근본적으로는 동일하지만 pet 프로퍼티가 존재하지 않을 수도 있습니다.
1
|
|
다음처럼 and같은 더미 getter를 사용하면 더 명확하게 체이닝할 수 있습니다.
1
|
|
assertion이 실패했을 때 더 명확한 내용을 보여주기 위해서 다음과 같이 각 매처에 추가적인 설명 파라미터를 전달하면 실패했을 경우 표시해줍니다. 이 추가적인 설명파라미터는 eql, equal, within, a, instanceof, above, below, match, length, property, ownProperty, include, includeEql 에서 사용할 수 있습니다.
1 2 3 4 5 |
|
Comments