Jasmine ile jQuery AJAX olaylarını nasıl doğrularım?


114

Jasmine'i temel jQuery AJAX istekleri için bazı BDD özelliklerini yazmak için kullanmaya çalışıyorum. Şu anda Jasmine'i bağımsız modda kullanıyorum (yani üzerinden SpecRunner.html). SpecRunner'ı jquery ve diğer .js dosyalarını yükleyecek şekilde yapılandırdım. Aşağıdakilerin neden çalışmadığına dair bir fikriniz var mı? has_returned, "yuppi!" uyarı iyi görünüyor.

describe("A jQuery ajax request should be able to fetch...", function() {

  it("an XML file from the filesystem", function() {
    $.ajax_get_xml_request = { has_returned : false };  
    // initiating the AJAX request
    $.ajax({ type: "GET", url: "addressbook_files/addressbookxml.xml", dataType: "xml",
             success: function(xml) { alert("yuppi!"); $.ajax_get_xml_request.has_returned = true; } }); 
    // waiting for has_returned to become true (timeout: 3s)
    waitsFor(function() { $.ajax_get_xml_request.has_returned; }, "the JQuery AJAX GET to return", 3000);
    // TODO: other tests might check size of XML file, whether it is valid XML
    expect($.ajax_get_xml_request.has_returned).toEqual(true);
  }); 

});

Geri aramanın arandığını nasıl test ederim? Jasmine ile eşzamansız jQuery'nin test edilmesiyle ilgili bloglara / materyallere yönelik her türlü ipucu çok takdir edilecektir.

Yanıtlar:


234

Sanırım yapabileceğiniz iki tür test var:

  1. Birim, AJAX isteğini taklit eden testleri (Jasmine'in casuslarını kullanarak), AJAX isteğinden hemen önce ve hemen sonrasında çalışan tüm kodunuzu test etmenizi sağlar . Sunucudan gelen bir yanıtı taklit etmek için Jasmine'i bile kullanabilirsiniz. Gerçek bir AJAX olmadığı için bu testler daha hızlı olacak ve eşzamansız davranışları ele almaları gerekmeyecek.
  2. Gerçek AJAX isteklerini gerçekleştiren entegrasyon testleri. Bunların eşzamansız olması gerekir.

Jasmine her iki tür testi de yapmanıza yardımcı olabilir.

İşte AJAX isteğini nasıl taklit edebileceğinize dair bir örnek ve ardından sahte AJAX isteğinin doğru URL'ye gittiğini doğrulamak için bir birim testi yazın:

it("should make an AJAX request to the correct URL", function() {
    spyOn($, "ajax");
    getProduct(123);
    expect($.ajax.mostRecentCall.args[0]["url"]).toEqual("/products/123");
});

function getProduct(id) {
    $.ajax({
        type: "GET",
        url: "/products/" + id,
        contentType: "application/json; charset=utf-8",
        dataType: "json"
    });
}

İçin 2.0 Jasmine kullanımı yerine:

expect($.ajax.calls.mostRecent().args[0]["url"]).toEqual("/products/123");

bu cevapta belirtildiği gibi

İşte bir AJAX isteği başarıyla tamamlandıktan sonra geri aramanın yürütüldüğünü doğrulayan benzer bir birim testi:

it("should execute the callback function on success", function () {
    spyOn($, "ajax").andCallFake(function(options) {
        options.success();
    });
    var callback = jasmine.createSpy();
    getProduct(123, callback);
    expect(callback).toHaveBeenCalled();
});

function getProduct(id, callback) {
    $.ajax({
        type: "GET",
        url: "/products/" + id,
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: callback
    });
}

İçin 2.0 Jasmine kullanımı yerine:

spyOn($, "ajax").and.callFake(function(options) {

bu cevapta belirtildiği gibi

Son olarak, entegrasyon amaçları için gerçek AJAX istekleri oluşturan entegrasyon testleri yazmak isteyebileceğinizin başka bir yerinde ima ettiniz. Bu, Jasmine'in zaman uyumsuz özellikleri kullanılarak yapılabilir: waits (), waitsFor () ve şunu çalıştırır ():

it("should make a real AJAX request", function () {
    var callback = jasmine.createSpy();
    getProduct(123, callback);
    waitsFor(function() {
        return callback.callCount > 0;
    });
    runs(function() {
        expect(callback).toHaveBeenCalled();
    });
});

function getProduct(id, callback) {
    $.ajax({
        type: "GET",
        url: "data.json",
        contentType: "application/json; charset=utf-8"
        dataType: "json",
        success: callback
    });
}

+1 Alex harika cevap. Aslında benzer bir sorunla karşılaştım ve bunun için bir soru açtığımda Ertelenmiş nesneyi kullanarak Ajax testi iste . Bir bakar mısın Teşekkürler.
Lorraine Bernard

12
Cevabınızın Jasmine için resmi belgelerin bir parçası olmasını gerçekten isterdim. Birkaç gündür beni öldüren bir soruna çok net cevap.
Darren Newton

4
Bu cevap gerçekten bu sorunun resmi cevabı olarak işaretlenmelidir.
Thomas Amar

1
En son çağrı bilgilerini almanın geçerli yolu $ .ajax.calls.mostRecent ()
camiblanch

1
Bunu düz JS ajax için nasıl uygularsınız?
Saatçi

13

Yasemin-ajax projesine bakın: http://github.com/pivotal/jasmine-ajax .

Bu, XHR katmanında (jQuery veya Prototype.js için) stub'ların hiçbir zaman dışarı çıkmaması için bir drop-in yardımcısıdır. Daha sonra istekle ilgili istediğiniz her şeyi bekleyebilirsiniz.

Ardından, tüm vakalarınız için fikstür yanıtları sağlamanıza ve ardından istediğiniz her yanıt için testler yazmanıza olanak tanır: başarı, başarısızlık, yetkisiz vb.

Ajax çağrılarını eşzamansız testler alanından çıkarır ve gerçek yanıt işleyicilerinizin nasıl çalışması gerektiğini test etmek için size çok fazla esneklik sağlar.


Teşekkürler @ yaseminbdd, yasemin-ajax projesi js kodumu test etmenin yolu gibi görünüyor. Peki ya sunucuya gerçek isteklerle, örneğin bağlantı / entegrasyon testleri için test etmek istersem?
mnacos

2
@mnacos yasemin-ajax, çoğunlukla birim testi için kullanışlıdır, bu durumda özellikle sunucuya yapılan çağrıyı önlemek istersiniz. Entegrasyon testleri yapıyorsanız, muhtemelen istediğiniz şey bu değildir ve ayrı bir test stratejisi olarak tasarlanmalıdır.
Sebastien Martin

7

İşte bunun gibi bir uygulama js için basit bir örnek test paketi

var app = {
               fire: function(url, sfn, efn) {
                   $.ajax({
                       url:url,
                       success:sfn,
                       error:efn
                   });
                }
         };

url regexp'ye göre geri aramayı çağıracak örnek bir test paketi

describe("ajax calls returns", function() {
 var successFn, errorFn;
 beforeEach(function () {
    successFn = jasmine.createSpy("successFn");
    errorFn = jasmine.createSpy("errorFn");
    jQuery.ajax = spyOn(jQuery, "ajax").andCallFake(
      function (options) {
          if(/.*success.*/.test(options.url)) {
              options.success();
          } else {
              options.error();
          }
      }
    );
 });

 it("success", function () {
     app.fire("success/url", successFn, errorFn);
     expect(successFn).toHaveBeenCalled();
 });

 it("error response", function () {
     app.fire("error/url", successFn, errorFn);
     expect(errorFn).toHaveBeenCalled();
 });
});

Tesekkurler dostum. Bu örnek bana çok yardımcı oldu! Jasmine> 2.0 kullanıyorsanız veCallFake için sözdiziminin spyOn (jQuery, "ajax") ve.callFake (/ * your function * /) olduğunu unutmayın;
João Paulo Motta

Emin değil bu bir versiyon konudur ama bir hata var ise .andCallFakekullanılır, .and.callFakebunun yerine. Teşekkürler.
OO

5

Jasmine ile ajax kodunu belirttiğimde, uzak aramayı başlatan bağlı işlev ne olursa olsun (örneğin $ .get veya $ ajax) casusluk yaparak sorunu çözüyorum. Ardından, üzerinde ayarlanmış geri aramaları alır ve ayrı ayrı test ederim.

İşte yakın zamanda aldığım bir örnek:

https://gist.github.com/946704


0

Jqueryspy.com'u deneyin Testlerinizi açıklamak için jquery gibi zarif bir sözdizimi sağlar ve ajax tamamlandıktan sonra geri aramaların test edilmesini sağlar. Entegrasyon testi için harikadır ve maksimum ajax bekleme sürelerini saniye veya milisaniye cinsinden yapılandırabilirsiniz.


0

Jasmine artık 2.4 sürümünde olduğu ve sürüm 2.0'dan birkaç işlev değiştiği için daha güncel bir cevap vermem gerektiğini hissediyorum.

Bu nedenle, AJAX isteğinizde bir geri arama işlevinin çağrıldığını doğrulamak için, bir casus oluşturmanız, ona bir callFake işlevi eklemeniz ve ardından casusu geri arama işlevi olarak kullanmanız gerekir. İşte nasıl gidiyor:

describe("when you make a jQuery AJAX request", function()
{
    it("should get the content of an XML file", function(done)
    {
        var success = jasmine.createSpy('success');
        var error = jasmine.createSpy('error');

        success.and.callFake(function(xml_content)
        {
            expect(success).toHaveBeenCalled();

            // you can even do more tests with xml_content which is
            // the data returned by the success function of your AJAX call

            done(); // we're done, Jasmine can run the specs now
        });

        error.and.callFake(function()
        {
            // this will fail since success has not been called
            expect(success).toHaveBeenCalled();

            // If you are happy about the fact that error has been called,
            // don't make it fail by using expect(error).toHaveBeenCalled();

            done(); // we're done
        });

        jQuery.ajax({
            type : "GET",
            url : "addressbook_files/addressbookxml.xml",
            dataType : "xml",
            success : success,
            error : error
        });
    });
});

AJAX'ınız bir hata döndürse bile Jasmine'in özellikleri mümkün olan en kısa sürede çalıştıracağından emin olmak için başarı işlevinin yanı sıra hata işlevini de yaptım.

Bir hata işlevi belirtmezseniz ve AJAX bir hata döndürürse, Jasmine bir hata atana kadar 5 saniye (varsayılan zaman aşımı aralığı) beklemeniz gerekir Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.. Ayrıca kendi zaman aşımınızı şu şekilde belirtebilirsiniz:

it("should get the content of an XML file", function(done)
{
    // your code
},
10000); // 10 seconds
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.