jasmine-nodeでNode.jsのBDD環境

jasmine-nodeがnpmで入るようになってたので使ってみた。
これを使うと完全にコマンドラインのみでJasmineを使うことが可能となり、テスト結果もブラウザではなくターミナルに表示される。
自分にとってはRailsやらPHPやらのサーバーサイドプログラミングで慣れ親しんだ形でございます。

しかしTitaniumをいじってたはずがいつの間にかNode.jsの世界に迷い込んでるんだけど、あんだこれ。

準備

インストール
npm install jasmine-node
ディレクトリの準備
mkdir myproject
cd myproject
mkdir lib
mkdir spec

libにはテスト対象の実コードを置く。
specにスペックファイルを置く。

実コードを置く場所を変えたければspecs.jsを書き換えればよい。

Jasmineとspecs.jsのコピー

スペックを走らせるのに必要なJasmineとspecs.jsをプロジェクトのディレクトリに持ってくる。

cp -r ~/.node_libraries/.npm/jasmine-node/active/package/lib/jasmine lib/
cp  ~/.node_libraries/.npm/jasmine-node/active/package/specs.js .

Jasmineは持ってこないでspecs.jsの中でパスを追加してやるという方法もある。
specs.shは内容を見るに使っても使わなくてもどっちでもいいと思う。自分は使わないことにした。

コード例

オブジェクトにスタイルをくっつけるクラスを書いてみた。

stylist.js

まずは実コード。
実際はテストファーストでスペックファイルとともに徐々に組み上げた。

var Stylist, exports;
Stylist = (function() {
  function Stylist() {}
  Stylist.prototype.styles = {};
  Stylist.prototype.decorate = function(target, options) {
    var key, value, _ref;
    if (!target) {
      return this.styles[options.style];
    }
    _ref = this.styles[options.style];
    for (key in _ref) {
      value = _ref[key];
      if (options.override || !target[key]) {
        target[key] = value;
      }
    }
    return target;
  };
  return Stylist;
})();
if (!exports) {
  exports = {};
}
exports.Stylist = Stylist;

クラスを定義してexportsしている。

exportsがなければexportsを定義している処理はNode.js以外の環境でも使うため。(具体的にはTitaniumで使うため)
Node.js以外で使わない場合は必要ない。

クラスを丸ごとexportsするのではなく、必要なメソッドのみをexportsすることもできる。
どっちのスタイルがポピュラーなのかまだちょっとよく分からない。

ちなみにこれは実はCoffeeScriptが生成したソースだったりする。

stylist_spec.js

次にスペックファイル。

var Stylist = require('stylist').Stylist;

describe('Stylist', function() {
  beforeEach(function() {
    this.stylist = new Stylist;
    this.stylist.styles["normal"] = {
      width: '50',
      height: '100'
    };
    this.stylist.styles["double height"] = {
      width: '50',
      height: '200'
    };
  });
  describe('オブジェクトをデコレートした場合', function() {
    it('オブジェクトに指定されたスタイルを付与すること', function() {
      var obj = { name: 'マネキン' };
      this.stylist.decorate(obj, {
        style: "double height"
      });
      expect(obj.width).toEqual('50');
      expect(obj.height).toEqual('200');
      expect(obj.name).toEqual('マネキン');
    });
    describe('オブジェクトにスタイルと同名のプロパティがあった場合', function() {
      it('プロパティを上書きしないこと', function() {
        var obj = {
          name: 'マネキン',
          width: '1000'
        };
        this.stylist.decorate(obj, {
          style: "double height"
        });
        expect(obj.width).toEqual('1000');
        expect(obj.height).toEqual('200');
        expect(obj.name).toEqual('マネキン');
      });
      it('上書きフラグが立っていればプロパティを上書きすること', function() {
        var obj = {
          name: 'マネキン',
          width: '1000'
        };
        this.stylist.decorate(obj, {
          style: "normal",
          override: true
        });
        expect(obj.width).toEqual('50');
        expect(obj.name).toEqual('マネキン');
      });
    });
  });
});

単なるJasmineのスペック。
requireしているところを除けばNode.js以外の環境でも動くはず。

(とはいえ実際のところは環境のポータビリティとかあんまり考えない方がほとんどのケースで幸せになれそうだけど)

実行
node specs.js

以下のようなシンプルな表示で結果が出る。なじみのある表示だ。

$ node specs.js
Started
...

Finished in 0.003 seconds
3 tests, 8 assertions, 0 failures

–verboseオプションを付けるとdescribeの内容がリストされてテスト結果の出力がちょっとだけ詳細になる。
しかしやや物足りない感じ。どうせならitの内容も出して欲しいものだ。

結果の表示はvowsの方がいかしてるね。

2011/01/18追記

手順をちょっと書き換えた。

前の記事

CoffeeScript

次の記事

ドメイン引っ越し中