2011-01-11 17 views
107

Próbuję użyć Jasmine do napisania niektórych specyfikacji BDD dla podstawowych żądań AJAX jQuery. Obecnie używam Jasmine w trybie autonomicznym (tj. Do SpecRunner.html). Skonfigurowałem SpecRunner, aby załadować pliki jquery i inne pliki .js. Wszelkich pomysłów, dlaczego poniższe nie działa? ma_wstecz nie staje się prawdą, nawet pomyślał "yuppi!" alarm pokazuje się dobrze.Jak mogę sprawdzić zdarzenia jQuery AJAX z Jasmine?

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); 
    }); 

}); 

Jak sprawdzić, czy wywołanie zwrotne zostało wywołane? Wszelkie wskazówki do blogów/materiałów związanych z testowaniem async jQuery z Jasmine będą bardzo mile widziane.

Odpowiedz

12

Spójrz na projekt jaśmin-ajax: http://github.com/pivotal/jasmine-ajax.

Jest to wtyczka pomocnicza, która (dla jQuery lub Prototype.js) jest umieszczana w warstwie XHR, aby żądania nigdy nie zgasły. Możesz wtedy oczekiwać wszystkiego, co chcesz o żądaniu.

Następnie pozwala przewidywać reakcje osprzętu dla wszystkich przypadków, a następnie napisać testy dla każdej odpowiedzi, które chcesz: sukces, porażka, nieuprawnione itp

Zajmuje Ajax woła o sferę badań i asynchronicznych zapewnia dużą elastyczność w testowaniu sposobu działania rzeczywistych procedur obsługi odpowiedzi.

+0

Dzięki @jasminebdd, projekt jaśmin-ajax wygląda jak sposób testowania mojego kodu js. Ale co jeśli chciałbym przetestować rzeczywiste żądania na serwer, np. do testów łączności/integracji? – mnacos

+2

@nnacos jaśmin-ajax jest głównie przydatny do testowania jednostkowego, w którym to przypadku chcesz uniknąć połączenia z serwerem. Jeśli przeprowadzasz testy integracyjne, prawdopodobnie nie jest to tym, czego potrzebujesz i powinno się je zaprojektować jako osobną strategię testowania. –

4

Kiedy określam kod ajax z Jasmine, rozwiązuję problem przez szpiegowanie funkcji zależnej inicjującej zdalne wywołanie (np. $ .get lub $ ajax). Następnie pobieram ustawione callbacki i testuję je dyskretnie.

Oto przykład ja gisted ostatnio:

https://gist.github.com/946704

227

myślę, istnieją dwa rodzaje testów, które możesz zrobić:

  1. Testy jednostkowe że fałszywy wniosek AJAX (przy użyciu szpiegów Jasmine) , umożliwiając przetestowanie całego kodu, który działa tuż przed żądaniem AJAX, a następnie tuż po. Możesz nawet użyć Jasmine do sfałszowania odpowiedzi z serwera. Testy te byłyby szybsze - i nie wymagałyby obsługi asynchronicznego zachowania - ponieważ nie działa żadna prawdziwa AJAX.
  2. Testy integracyjne, które wykonują prawdziwe żądania AJAX. Te muszą być asynchroniczne.

Jaśmin może pomóc w wykonaniu obu testów.

Oto przykład tego, jak można fałszywy wniosek AJAX, a następnie napisać badanej jednostki w celu sprawdzenia, że ​​sfałszowane żądanie AJAX szło do prawidłowego adresu URL:

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" 
    }); 
} 

Dla Jasmine 2.0 użycie zamiast:

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

jak zauważono w this answer

Oto test podobna jednostka, która weryfikuje swoją zwrotnego została wykonana, na żądanie AJAX ukończenie powodzeniem:

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 
    }); 
} 

Dla Jasmine 2.0 użyj zamiast tego:

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

jak zanotowano w this answer

Wreszcie, w innym miejscu napomknąłeś, że możesz chcieć pisać testy integracyjne, które wymagają prawdziwych żądań AJAX - do celów integracji. Można to zrobić za pomocą Asyncronous możliwości Jasmine: czeka(), waitsFor() i działa():

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 
    }); 
} 
+0

+1 Dobra odpowiedź Alex. Właściwie natrafiłem na podobny problem, dla którego otworzyłem pytanie [Test Ajax z wykorzystaniem obiektu Odroczony] (http://stackoverflow.com/questions/12080087/test-ajax-request-using-the-deferred-object). Mógłbyś rzucić okiem? dzięki. –

+12

Naprawdę chciałbym, aby twoja odpowiedź była częścią oficjalnej dokumentacji Jasmine. Bardzo jasna odpowiedź na problem, który zabija mnie przez kilka dni. –

+0

Doskonała odpowiedź i przykład. Dziękuję Ci. –

0

Spróbuj jqueryspy.com Zapewnia eleganckie jquery jak składni, by opisać swoje testy i pozwala zwrotnych do badania po ajax jest kompletny. Jest świetny do testowania integracji i można skonfigurować maksymalne czasy oczekiwania ajax w sekundach lub milisekundach.

5

tutaj prosty przykład testu apartament jeszcze przez js aplikacji takich jak ten

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

zestaw testowy próbki, które będą wymagały zwrotnego na podstawie url regexp

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(); 
}); 
}); 
+0

Dzięki stary. Ten przykład bardzo mi pomógł! Pamiętaj, że jeśli używasz Jasmine> 2.0, składnia dla andCallFake to spyOn (jQuery, "ajax"). I.callFake (/ * twoja funkcja * /); –

0

czuję się muszę aby zapewnić bardziej aktualną odpowiedź, ponieważ Jasmine jest teraz w wersji 2.4 i kilka funkcji zmieniło się z wersji 2.0.

Aby sprawdzić, czy w Twoim żądaniu AJAX została wywołana funkcja zwrotna, musisz utworzyć szpiega, dodać do niego funkcję callFake, a następnie użyć szpiega jako funkcji zwrotnej. Oto jak to działa:

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 
     }); 
    }); 
}); 

Zrobiłem podstęp dla funkcji sukcesu, jak również funkcji błędu, aby upewnić się, że Jasmine potrwa specyfikacje jak najszybciej, nawet jeśli AJAX zwraca błąd.

Jeśli nie określisz funkcji błędu, a twoja AJAX zwróci błąd, będziesz musiał poczekać 5 sekund (domyślny przedział czasu), aż Jasmine zgłasza błąd Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.. Możesz również określić swój własny limit czasu w następujący sposób:

it("should get the content of an XML file", function(done) 
{ 
    // your code 
}, 
10000); // 10 seconds 
Powiązane problemy