簡単にするために(本物は複雑で無関係です)、現在のウィンドウのクエリ文字列を返すユーティリティ関数があるとしましょう。
var someUtilityFunction = () {
return window.location.search.substring(1);
};
ここで、この関数をqUnitで単体テストしたいと思います(テストハーネスが関連しているかどうかはわかりません)。
test('#1 someUtilityFunction works', function () {
// setup
var oldQS = window.location.search;
window.location.search = '?key1=value1&key2=value2&key3=value3';
var expectedOutput = 'key1=value1&key2=value2&key3=value3';
// test
equals(someUtilityFunction(),
expectedOutput,
'someUtilityFunction works as expected.');
// teardown
window.location.search = oldQS;
});
ここでの問題は、window.location.search
を別のクエリ文字列に設定すると、ページが再読み込みされ、本質的に無限の要求ループに入るということです。 window.locationオブジェクトをモックアウトする方法はありますかなしsomeUtilityFunction
関数に変更を加えますか?
数日前に同じ問題が発生しました。主に2つのアプローチがあります:
これは(もしあれば)最善の解決策ではないかもしれませんが、モックを簡単にするためにwindow
オブジェクトを関数に渡すことを検討してください。さらに良いことに、クロージャを使用してコードをカプセル化します。これには、さらにいくつかの利点があります。
ウィンドウオブジェクトをローカル変数にモックする関数内にすべてのコードをラップできます。基本的に2つの可能性もあります。
これがモックだとします。
var customWindow = {
location: {
search: "",
hash: ""
}
};
var someUtilityFunction;
(function(window) {
// window is now shadowed by your local variable
someUtilityFunction = () {
return window.location.search.substring(1);
};
})(customWindow);
これにより、グローバルwindow
がローカルwindow
でシャドウされます。
with
ステートメントを使用します私は通常強く反対しますが、それはここで多くの問題を本当に解決することができます。基本的にスコープを再マップするため、環境を非常に簡単にモックできます。
// first some more preparation for our mock
customWindow.window = customWindow;
with(customWindow) {
// this still creates the var in the global scope
var someUtilityFunction = () {
// window is a property of customWindow
return window.location.search.substring(1);
};
// since customWindow is our scope now
// this will work also
someUtilityFunction = () {
// location is a property of customWindow too
return location.search.substring(1);
};
}
ちなみに、search
プロパティがhash
プロパティと同じ症状に苦しんでいるかどうかはわかりません。つまり、疑問符が含まれている場合と含まれていない場合があります。しかし、あなたは使用を検討したいかもしれません
window.location.search.replace(/^\?/, "");
の代わりに
window.location.substr(1);
_window.history.pushState
_を使用してある程度の成功を収めました。 このStackOverflowの回答 を参照してください。単体テストごとに、関数setQueryString('var=something')
を呼び出し、次のように実装します。
_function setQueryString(queryString) {
window.history.pushState({}, '', '?' + queryString);
}
_
QUnit.moduleのafterEach
メソッドを使用してクエリ文字列をクリアする必要があります。そうしないと、クエリ文字列が最終テストの値に設定され、奇妙な結果が得られます。