2012-02-24 15 views
6

私たちは、JS重いウェブアプリケーション用のQUnit JavaScriptテストを実装しようとしています。私たちは、jQuery AJAXリクエストを含むメソッドを正常にテストする方法を見つけるのに苦労しています。私たちは、好ましくは、代わりに本物のsomeURL.phpのスタブURLで、fireメソッドをテストする方法を見つけようとしているQUnitでユニットテストAJAXリクエスト

var X = function() { 
    this.fire = function() { 
     $.ajax("someURL.php", { 
      data: { 
       userId: "james" 
      }, 
      dataType: "json", 
      success: function(data) { 
       //Do stuff 
      } 
     }); 
    }; 
}; 
var myX = new X(); 
myX.fire(); 

:たとえば、私たちは以下のコンストラクタ関数(明らかにこれは非常に単純化した例がある)を持っています。

現時点で私には唯一明らかな解決策は、コンストラクタ関数の引数としてURLとsuccessコールバックを追加することです。こうして、テストでは、Xという新しいインスタンスを作成し、スタブURLを渡し、スタブが応答を返すときに実行するコールバックを渡すことができます。例:

test("Test AJAX function", function() { 
    stop(); 
    var myX = new X(); 
    //Call the AJAX function, passing in the stub URL and success callback 
    myX.fire("stub.php", function(data) { 
     console.log(data); 
     start(); 
    }); 
}); 

しかし、これは非常に素晴らしい解決策のようには見えません。より良い方法がありますか? jQueryを使って

答えて

9

あなたはより多くのハンドラを追加することができますので、あなたはオプションで定義するだけで、単一のsuccesscompleteerrorものより(下記参照)、約束として.ajax()戻っていることXHRオブジェクトを使用することができます。したがって、非同期関数がxhrオブジェクトを返すことができる場合は、テスト固有のハンドラを追加できます。

URLはちょっと面倒です。私は、実際のサーバからコピーされた応答を提供するlocalhost上の非常に単純なNodeサーバを設定することがあります。同じサーバーからテストスイートを実行する場合、URLは運用サーバーではなくテストサーバーを起動するための絶対パスである必要があります。そして、あなたはまた、サーバーがそれらを見ているように、要求自体の記録を取得します。あるいは、コードがどのようにそれを処理しているかを見たい場合には、テストサーバが意図的にエラーや悪いレスポンスを送り返すようにすることもできます。

しかし、それはかなり複雑なソリューションです。 URLをテストスイートから再定義できる場所に定義するほうが簡単です。例えば:

/* in your code */ 
var X = function() { 
    this.fire = function() { 
     return $.ajax({ url: this.constructor.url, ... }); 
    }; 
}; 
X.url = "someURL.php"; // the production url 

/* in your tests */ 
X.url = "stub.php"; // redefine to the test url 

また、QUnitはあなたのためにstop()を呼び出すasyncTest機能を有しています。小さなヘルパーを追加して、いつ再起動するかを把握してください。あなたはかなり良い解決策を得ています。

は、ここで私は基本的に

// create a function that counts down to `start()` 
function createAsyncCounter(count) { 
    count = count || 1; // count defaults to 1 
    return function() { --count || start(); }; 
} 

// .... 

// an async test that expects 2 assertions 
asyncTest("testing something asynchronous", 2, function() { 
    var countDown = createAsyncCounter(1), // the number of async calls in this test 
     x = new X; 

    // A `done` callback is the same as adding a `success` handler 
    // in the ajax options. It's called after the "real" success handler. 
    // I'm assuming here, that `fire()` returns the xhr object 
    x.fire().done(function(data, status, jqXHR) { 
     ok(data.ok); 
     equal(data.value, "foobar"); 
    }).always(countDown); // call `countDown` regardless of success/error 
}); 

countDown前に何から指定したゼロにカウントダウンし、その後start()を呼び出す関数ですやったものです。この場合、1つの非同期コールがあるので、countDownはそれからカウントダウンします。これは、AJAXの呼び出しが完了した時点で、そのコールバックがalwaysコールバックとして設定されているため、終了しても終了します。
asyncTestには2つのアサーションがあると言われているため、アサーションが実行されないため、.done()コールバックが呼び出されないとエラーが報告されます。コールが完全に失敗すると、そのこともわかります。エラーが発生したときに何かを記録する場合は、.fail()コールバックをプロミスチェーンに追加することができます。

+0

これは素晴らしいです。ありがとうございました:) –

2

jQuery spyをお試しください。私はajaxをテストするためのjQueryの使い慣れた構文を使用する簡単な方法を作成しました。

Check this link

3

それは(とすべきである)、サーバ側から分離して実行することができますユニットテストだ場合、あなたは単にどんな行動をシミュレートする$.ajaxを「置き換える」ことができます。 一つの簡単な例:

test("Test AJAX function", function() { 
    // keep the real $.ajax 
    var _real_ajax = $.ajax; 

    // Simulate a successful response 
    $.ajax = function(url, opts) { 
    opts.success({expected: 'response'}); 
    } 

    var myX = new X(); 
    // Call your ajax function 
    myX.fire(); 
    // ... and perform your tests 

    // Don't forgot to restore $.ajax! 
    $.ajax = _real_ajax; 
}); 

明らかにあなたはまた、スタブURL /データと実際のAJAX呼び出しを実行することができます。

// Simulate a successfully response 
$.ajax = function(url, opts) { 
    opts.success = function(data) { 
    console.log(data); 
    start(); 
    } 
    _real_ajax('stub.php', opts) 
} 

あなたは複雑な応答を持っていない場合、私はので、最初のアプローチを好みますそれはより速く、理解しやすいです。
しかし、別の方法でAjaxロジックを独自のメソッドに入れて、テスト中に簡単にスタブすることもできます。

+0

私のテストをサーバ側から隔離するために、私はこのライブラリで多くの成功を収めました。https://github.com/jakerella/jquery-mockjax –