Skip to content

Instantly share code, notes, and snippets.

@kozy4324
Last active October 6, 2015 20:48
Show Gist options
  • Save kozy4324/3051422 to your computer and use it in GitHub Desktop.
Save kozy4324/3051422 to your computer and use it in GitHub Desktop.
vowsでユニットテストを書くよ

vowsの特徴

  • BDDスタイル
  • 構造的なスペック記述
  • topicによる対象の明示化
  • 非同期処理(特にNodeのconventionに即している非同期処理)への適応
  • 構造によるparallelな実行とsequentialな実行
  • 標準のAssertモジュールを拡張したアサーション

vows内で認識すべき要素

Batch

Contextを保持したオブジェクト、keyがそのContextへの記述になる

Context

Topic, Vow, Contextを保持したオブジェクト、Topicは任意、Contextはネストして保持することができる

Topic

Context内でkeyが"topic"のvalue、値 or 関数の戻り値 or 関数内でコールバックされる値がそのContext内のVowに渡される

Vow

assertを記述する関数、keyがそのVowへの記述になる

vowsによる典型的パターン

'オブジェクト -> そのオブジェクトのメソッドや振る舞いにフォーカスするのを構造的に': {
  topic: new SomeObject,
  'objectの状態をassert': function(obj) {...},

  'メソッドにフォーカスで子コンテキストに展開': {
    topic: function(obj) { return obj.someMethod() },
    '戻り値は○○だ': function(retVal) {...},
  },

  '非同期処理などの振る舞いも子コンテキストに展開': {
    topic: function(obj) { obj.asyncMethod( this.callback ) },
    '引数が○○でコールバックされる': function(err, val) {...}
  }
}

vowsでこのケースはどう書く?

  • 例外の振る舞い、assert.throw()あるけど、主題をtopicに書く思想と合ってなくないか?(topicの例外をVowに渡すのも若干分かりづらいし...)

vowsのここが物足りない

  • スタブやモックがない(JasmineでいうSpy Object)
  • 振る舞い記述のDSLとしてはAssertion形式よりMatcher形式のほうが好み
var vows = require('vows'),
assert = require('assert');
vows.describe('Suiteについての記述を書く').addBatch({
'Contextへの記述を書く': {
topic: '値のTopic',
'これはVow、引数にはtopicの値が渡ってくる': function (topic) {
assert.equal(topic, '値のTopic');
}
},
'Batchは複数のContextを保持できる': {
topic: function() {
return '戻り値がVowに渡る';
},
'topicが関数で戻り値がある場合はそれが渡ってくる': function (topic) {
assert.equal(topic, '戻り値がVowに渡る');
},
'Vowは複数保持できる': function (topic) {
assert.include(topic, 'Vow');
},
'ネストしたContext': {
'TopicがないContextの場合は親ContextのTopicが渡ってくる': function(topic) {
assert.equal(topic, '戻り値がVowに渡る');
}
},
'ネストしたContextでのTopic関数への引数': {
topic: function(parent_topic) {
return parent_topic + ' 引数に親からのtopicが渡る';
},
'topicの引数に親Topicが渡ってくる': function(topic) {
assert.equal(topic, '戻り値がVowに渡る 引数に親からのtopicが渡る');
},
'さらにContextをネスト': {
topic: function(parent_parent_topic, parent_topic) {
return [parent_parent_topic, parent_topic];
},
'ネストするとtopic関数に全ての親のtopicが渡ってくる': function(topic) {
assert.deepEqual(topic, ['戻り値がVowに渡る 引数に親からのtopicが渡る', '戻り値がVowに渡る']);
}
},
'値が関数ではなく文字列のVowはpending': 'pending理由を記述'
},
},
'非同期処理のTopicの書き方': {
topic: function() {
require('fs').stat('./a.js', this.callback);
},
'topic関数の戻り値がundefinedの場合は非同期処理': function(err, stat) {
assert.isNull(err);
assert.isObject(stat);
},
'this.callbackの呼ばれた引き数がVowに渡る': function(err, stat) {
assert.isNotZero(stat);
},
'Vow関数の引き数の数が1つの場合はerrorオブジェクトが省略される': function(stat) {
assert.isNotZero(stat);
}
},
// topic関数の戻り値がEventEmitterパターンは割愛...
'topicで例外が発生したら?': {
topic: function() {
throw '例外をthrow';
return 'このreturnは実行されない';
},
'throwされた例外がVowに渡る': function(err) {
assert.equal(err, '例外をthrow');
}
}
}).run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment