2009-11-26 4 views
4

J'ai une question concernant les tests unitaires de la fonction document.ready de jQuery().Test d'unité Fonction jQuery document.ready

Actuellement, j'ai 2 scénarios dans mon code:

function myFunction() 
{ 
    $(document).ready(function() { ... }); 
} 

Et:

$(document).ready(function() 
{ 
    // some really long setup code here 
}); 

J'ai essayé d'écrire un test unitaire pour le premier scénario, mais je ne pouvais pas le faire à exécuter dans la fonction document.ready. En ce qui concerne le second scénario, je n'ai pas encore trouvé de moyen de le tester (j'ai du mal à trouver un moyen de le tester ainsi que la syntaxe). Donc, en supposant que je ne puisse pas changer le code source, y a-t-il des façons de tester ces fonctions? (en supposant que c'est une bonne idée de les tester)

Merci.

+0

Que voulez-vous tester exactement? Juste tester le code pourquoi ne devriez-vous pas tester ce que fait votre code? – powtac

+0

J'essaie de tester la logique dans $ (document) .ready (function() {// tester ces codes}) ;. J'utilise JsTestDriver pour tester mon javascript. En ce moment j'ai des difficultés à atteindre le bloc document.ready. – BeraCim

Répondre

6

Vous n'avez pas besoin de tester $(document).ready car il fait partie du framework et est déjà testé à l'unité. Lors de l'écriture des tests unitaires, vous devez tester deux choses:

  1. Votre interaction avec le framework. Cela inclut des choses comme s'assurer que vous appelez les bonnes fonctions avec les bons paramètres.
  2. Votre propre code - que votre code fait la bonne chose.

Donc, ce que vous devez vraiment faire est de vous assurer que tout code qui est appelé par $(document).ready est correct.

function myInit(){ 
//... 
} 
function myFunction() 
{ 
    $(document).ready(myInit); 
} 

Tout ce que vous devez faire est maintenant fonction de test unitaire myInit.

Ce que vous pouvez faire est simulé sur $.ready fonction pour vous assurer que vous appelez le:

var readyCalled = false; 
$.ready = function(func){ 
    readyCalled = (myInit == func); 
} 

//Your code containing `myInit` will get executed somewhere here 
//.... 
//Then test: 
test("Should have called ready", function() { 
ok(readyCalled, "ready should have been called with myInit as a parameter.") 
}); 
+1

@Igor: pour votre exemple, que se passe-t-il s'il y a un tas de logique qui n'appelle pas les fonctions externes (comme myInit)? J'ai essayé d'écrire un test unitaire pour tester myFunction, mais je ne pouvais pas entrer dans le document.ready (syntaxe sage). Il y a beaucoup de $ (document) .ready (function() {}); dans mon code, d'où le besoin de les tester. Et puis on m'a dit que je n'avais pas besoin de tester document.ready. D'où je suis confus. Merci. – BeraCim

+0

@BeraCim Pour utiliser cette solution, vous pouvez refactoriser ces fonctions anonymes en fonctions nommées afin de pouvoir y accéder à partir de tests unitaires, sauf que cela viole l'une des contraintes de votre question ("en supposant que je ne peux pas changer le code source"). – apollodude217

0

La fonction qui enregistre le gestionnaire sur prêts devrait enregistrer une autre fonction, pas un codeblock anonyme. Ensuite, vous pouvez tester le code qui appelle $ .ready() distinct du code qui s'exécute sur prêt. Vous avez donc:

  1. Un test pour vérifier la bonne fonction est définie comme le gestionnaire prêt
  2. Un autre test pour vérifier le gestionnaire prêt fait l'étoffe

Pour tester le scénario 1, vous Je vais devoir injecter un double de test pour jQuery. C'est difficile comme si vous redéfinissez $ ou jQuery, les chances sont que vous allez bousiller un autre code qui repose sur lui pour d'autres traitements (comme le coureur de test). En même temps, votre code peut toujours vouloir appeler directement jQuery lorsqu'il utilise des méthodes utilitaires comme la concaténation de tableau. Tout modèle d'inversion de contrôle devrait cependant répondre à cette question (http://martinfowler.com/articles/injection.html).

Quoi qu'il en soit, voici un code en utilisant l'injection de constructeur (en utilisant JSMock pour la bibliothèque moqueur, et QUnit (de jQuery) pour le coureur de test):

// the code 

var createComponent = function(_$) { 
    var that = {}; 

    that.OnStart = function() { 
     _$.ready(this.OnReady); 
    }; 

    that.OnReady = function() { 
    }; 

    return that; 
}; 

// the test 

test("OnStart associates the ready handler", function() { 

    var sut; 

    var mock$ = mc.createMock($); 
    mock$.expects().ready(isA.TypeOf(Function)).andStub(function(callback) { 
     equals(callback, sut.OnReady); 
    }); 

    sut = createComponent(mock$); 

    sut.OnStart(); 

    mc.verify(); 
}); 

test("OnReady does the right stuff", function() { 
    //etc 
}); 

J'utilise ce schéma général pour tous les gestionnaires d'événements JS ...Vous préférerez peut-être utiliser des classes de type prototype. Lorsque vous passez des fonctions en tant que paramètres à jQuery, vous devez être conscient que la valeur "this" ne sera pas définie par jQuery lorsque ces rappels sont appelés. Dans le test, cela se brise parce que les égales (callback, sut.OnReady) ne passent plus. Pour résoudre ce problème, vous devez faire en sorte que les gestionnaires d'événements dirigent les membres de chaque instance. Vous pouvez imaginer quand il y en a plusieurs, alors c'est bien d'avoir un utilitaire qui en prend une liste, mais cela démontre que 'OnReady' est un membre qui ne compte pas sur 'ceci'.

var Component = function(_$) { 
    this._$ = _$; 

    // repeat for each event handler thats tested 
    this.OnReady = function() { 
     Component.prototype.OnReady.apply(this); 
    } 
} 

Component.prototype.Start = function() { 
    this._$.ready(this.OnReady); 
} 

Component.prototype.OnReady = function() { 
} 
+0

Il n'y a donc aucun moyen de tester le bloc de code anonyme en dehors de prendre le code à une fonction distincte? – BeraCim

+0

Vous pouvez utiliser la fonctionnalité JSMock etStub() pour enregistrer le callback passé, puis appeler ce callback depuis le même test. Ce ne serait pas souhaitable cependant, comme maintenant vous avez un test vérifiant des choses séparées (menant à la mauvaise localisation des défauts http://xunitpatterns.com/Goals%20of%20Test%20Automation.html#Defect%20Localization) –

Questions connexes