JavaScriptのユニットテストを上手にしようとしています。私は次のコードを持っています:
_var categoryVal = $('#category').val();
if (categoryVal === '') {
doSomething();
}
_
私のテストランナーはページに_#category
_入力がないので、ここでjQueryセレクターをスタブ/モックアウトするにはどうすればよいですか? jasmin と sinon の両方のドキュメントを見てきましたが、スタブがオブジェクトで動作するため、ここでそれらを機能させる方法を理解できません。_$
_はそうではありません。
ここでの問題は、$()
がメソッドval()
でオブジェクトを返す関数であるということです。したがって、メソッドvalを持つスタブオブジェクトを返すには、$()をスタブする必要があります。
_$ = sinon.stub();
$.withArgs('#category').returns(sinon.stub({val: function(){}}));
_
ただし、ここでの主な間違いは、テストするコードで関数$()を呼び出して新しいインスタンスを作成することです。どうして?クラスに新しいインスタンスを作成せず、コンストラクターに渡すことをお勧めします。入力から値を取得し、それを2倍にして、別の値に書き戻す関数があるとします。
_function doubleIt(){
$('#el2').val(('#el1').val() *2);
}
_
この場合、$()
を呼び出して2つの新しいオブジェクトを作成します。ここで、モックとスタブを返すために$()
をスタブする必要があります。次の例を使用すると、これを回避できます。
_function doubleIt(el1, el2){
el2.val(el1.val() *2);
}
_
前者の場合、スタブを返すために$をスタブする必要がありますが、後者の場合、スタブとスパイを関数に簡単に渡すことができます。
したがって、2番目のシノンテストは次のようになります。
_var el1 = sinon.stub({val: function(){}});
el1.returns(2);
var el2 = sinon.spy({val: function(){}}, 'val')
doubleIt(el1, el2)
assert(el2.withArgs(4).calledOnce)
_
したがって、ここにはdom要素がないため、アプリと同じdomを作成する必要なしに、アプリケーションロジックをテストするだけで済みます。
jQueryは内部でcssセレクターエンジンSizzleを使用し、分離されているため、フックする場所はわずかです。これを傍受して、domとの相互作用を回避できます。
jQuery.findは、必要なものに応答するために変更する重要なものです。 Sinonはここで使用するか、一時的に機能を交換することができます。
例えば
existingEngine = jQuery.find
jQuery.find = function(selector){ console.log(selector) }
$(".test")
//>> ".test"
jQuery.find = existingEngine
フォールバックを使用して特定のキャッチ条件を適用することもできます
existingEngine = jQuery.find
jQuery.find = function(selector){
if(selector=='blah'}{ return "test"; }
return existingEngine.find.apply(existingEngine, arguments)
}
最近の作業では、domノードのように応答するダミーオブジェクトを作成し、それをjQueryオブジェクトでラップしました。これにより、val()に正しく応答し、期待するすべてのjqueryメソッドが存在します。私の場合、フォームから値を取得するだけです。実際の操作を行う場合は、これよりも賢くする必要があるかもしれません。おそらく、期待したものを表すjQueryを使用して一時的なdomノードを作成します。
obj = {
value: "blah",
type: "text",
nodeName: "input",
}
$(obj).val(); // "blah"
Backbone.jsとJasminを使用している場合は、ビューをテストするための非常に優れたガイドがあります。 [表示]セクションまで下にスクロールします。
http://tinnedfruit.com/2011/04/26/testing-backbone-apps-with-jasmine-sinon-3.html
確かに、スタブはオブジェクトを操作します。そのようにビュースタブを作成するのがポイントだと思います。
this.todoViewStub = sinon.stub(window, "TodoView")
.returns(this.todoView);
後でビューをレンダリングできるようにするためだけです。
this.view.render();
つまり、テストランナーのDOMに '#category' divを追加して、$がそれに作用できるようにします。 '#category' divがthis.viewにない場合は、分離されたテストを実行するtest.htmlページを作成できます。これは、Javascript MVCフレームワークの一般的なパターンであり、私はそのバックボーンに慣れています。
簡単なJMVCアプリケーション構造の例を次に示します。
/todo
/models
todo.js
/list
/views
init.tmpl
listItem.tmpl
list.css
list.js (Controller)
unitTest.js (Tests for your list.)
list_test.html (A html for your unit tests to run on.)
この設定では、ビューの1つに「#category」divがまだ含まれていない場合は、list_test.htmlに含めることができます。