2010-08-23 7 views
2

Je suis en train de tester certaines librairies javascript que j'ai construites en utilisant harmony de ruby. Tout fonctionne parfaitement sauf les appels AJAX - est-ce que quelqu'un a des idées pour y parvenir?Tests unitaires asynchrones en Ruby

Mon code ressemble à ceci (j'utilise RightJS):

my.js

function makerequest(argument) { 
    new Xhr('http://mysite.com/some/jsonp'),{ 
     jsonp: true, 
     params: {something: argument}, 
     onSuccess: function() { 
      // Calls a function defined outside my library 
      parse_response(this.json) 
     } 
    }).send() 
} 

test_makerequest.rb

require 'rubygems' 
require 'harmony' 
require 'test/unit' 
require 'shoulda' 

class RequestTest < Test::Unit::TestCase 
    context "The requesty thing" do 
     setup do 
      @page = Harmony::Page.new 
      @page.load(File.expand_path('js/my.js')) 
     end 

     should "get stuff from mysite.com" do 
      # Here I need to define a 'parse_response' which this 
      # should section will wait for and then do an 'assert' 
      # on the results. 
      results = callback_to_get_results_from__make_request 
      @page.execute('make_request("an argument")') 
      assert results == {'foo' => 'bar'} 
     end 
    end 
end 

Alors oui, mon question est, comment dois-je attribuer results ci-dessus de telle sorte que je peux obtenir la res ults du rappel asynchrone?

Répondre

0

Les appels asynchrones sont généralement problématiques avec les tests unitaires JS. Je l'ai résolu dans le passé en rendant les appels XHR effectivement synchrones en bloquant le thread principal jusqu'à ce que l'appel XHR réussisse. Comment faire cela varie en fonction de votre cadre, et je ne suis pas familier avec Harmony et RightJS. Toutefois, la logique devrait ressembler à ceci:

  1. Surchargez votre méthode XHR pour qu'elle maintienne un verrou/mutex. Le verrou peut être un simple booléen. Quand un XHR est en cours, le verrou sera true, quand aucun XHR n'est en cours, le verrou sera false.
  2. Dans votre test, avant d'exécuter votre assertion, ajoutez une boucle qui exécute votre XHR, puis attend que le verrou disparaisse.
  3. Une fois la boucle terminée, vous serez certain que le XHR est terminé et vous pourrez exécuter votre assertion.

Le but de cette approche est d'éviter de modifier votre code, ce qui invaliderait vos tests. Malheureusement, cela signifie également que vous ne pouvez pas tester la valeur de retour elle-même, mais je pense que ce sera une mise en garde de toute stratégie qui ne modifie pas votre code.

Une autre approche serait d'exécuter réellement vos tests de manière asynchrone - ie. associez votre assertion au rappel onSuccess en utilisant AOP. Cependant, de nombreuses suites de tests ne fonctionnent pas bien avec les tests asynchrones, car la configuration d'un test peut commencer avant le démontage du test précédent (c'est-à-dire parce que le test précédent attend toujours l'appel asynchrone). Une dernière approche consisterait à se moquer de tous les appels asynchrones. C'est à dire. Remplacez simplement XHR et demandez à votre test d'affirmer qu'il a été appelé avec les bons arguments. Je pourrais favoriser cette approche si j'ai des tests d'intégration qui passent par toute la pile asynchrone.