18

簡単にするために(本物は複雑で無関係です)、現在のウィンドウのクエリ文字列を返すユーティリティ関数があるとしましょう。

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ますか?

4

2 に答える 2

19

数日前に同じ問題が発生しました。主に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);
于 2012-08-09T20:36:06.427 に答える
3

を使用してある程度の成功を収めましたwindow.history.pushStateこのStackOverflowの回答を参照してください。単体テストごとに、次のsetQueryString('var=something')ように実装する関数を呼び出します。

function setQueryString(queryString) {
  window.history.pushState({}, '', '?' + queryString);
}

QUnit.moduleのメソッドを使用してクエリ文字列をクリアする必要がありますafterEach。そうしないと、クエリ文字列が最終テストの値に設定され、奇妙な結果が得られます。

于 2015-07-09T12:19:46.117 に答える