J'essaie d'incorporer des tests unitaires JavaScript dans mon processus de construction automatisé. Actuellement, JSUnit fonctionne bien avec JUnit, mais il semble être un abandonware et manque d'un bon support pour AJAX, le débogage et les délais d'attente.
Quelqu'un a-t-il eu la chance d'automatiser (avec ANT) une bibliothèque de tests unitaires telle que le test YUI, le QUnit de JQuery ou jQUnit ( http://code.google.com/p/jqunit/ )?
Remarque: J'utilise une bibliothèque personnalisée AJAX, donc le problème avec DOH de Dojo est qu'il vous oblige à utiliser leurs propres appels de fonction et gestionnaires d'événements AJAX) travailler avec tout AJAX test unitaire.
Il existe de nombreux frameworks de test unitaire javascript (jsUnit, scriptaculous, ...) mais jsUnit est le seul que je connaisse qui puisse être utilisé avec une construction automatisée.
Si vous effectuez un "vrai" test unitaire, vous ne devriez pas avoir besoin de AJAX. Par exemple, si vous utilisez un framework ajax RPC tel que DWR, vous pouvez facilement écrire une fonction factice:
function mockFunction (someArg, callback) { var result = ...; // certains traitements setTimeout (
function () {callback (result); }, 300 // une fausse latence
); }
Et oui, JsUnit gère les timeouts: Simulation du temps dans les tests jsUnit
Je suis sur le point de commencer à faire Javascript TDD sur un nouveau projet sur lequel je travaille. Mon plan actuel est d'utiliser qunit pour effectuer les tests unitaires. Pendant le développement, les tests peuvent être exécutés en actualisant simplement la page de test dans un navigateur.
Pour une intégration continue (et assurer l'exécution des tests dans tous les navigateurs), j'utiliserai Selenium pour charger automatiquement le faisceau de test dans chaque navigateur et lire le résultat. Ces tests seront exécutés à chaque enregistrement au contrôle de code source.
Je vais également utiliser JSCoverage pour obtenir une analyse de la couverture du code des tests. Cela sera également automatisé avec Selenium.
Je suis actuellement en train de mettre cela en place. Je mettrai à jour cette réponse avec des détails plus exacts une fois que la configuration sera mise au point.
Outils de test:
Je suis un grand fan de js-test-driver
Il fonctionne bien dans un environnement CI et est capable de capturer des navigateurs réels pour des tests inter-navigateurs.
J'ai récemment lu un article de Bruno utilisant JsUnit et créant un framework JsMock en plus de cela ... très intéressant. Je pense utiliser son travail pour commencer à tester mon code Javascript.
Mock Javascript ou How to unit test Javascript outside the Browser environment
Je viens de j'ai obtenu Hudson CI pour exécuter JasmineBDD (sans tête), au moins pour les tests unitaires javascript purs.
(Hudson exécutant Java via Shell, exécutant Envjs, exécutant JasmineBDD.)
Je ne l'ai pas encore pour jouer à Nice avec une grande bibliothèque, comme un prototype.
Regardez YUITest
Je suis d'accord pour dire que jsunit est en train de mourir sur la vigne. Nous venons de terminer de le remplacer par YUI Test.
Semblable à l'exemple utilisant qUnit, nous exécutons les tests avec Selenium. Nous exécutons ce test indépendamment de nos autres tests Selenium simplement parce qu'il n'a pas les dépendances des tests de régression d'interface utilisateur normaux (par exemple, le déploiement de l'application sur un serveur).
Pour commencer, nous avons un fichier javascript de base qui est inclus dans tous nos fichiers html de test. Cela gère la configuration de l'instance YUI, du lanceur de test, de l'objet YUI.Test.Suite ainsi que de Test.Case. Il dispose d'une méthode accessible via Selenium pour exécuter la suite de tests, vérifier si le lanceur de test est toujours en cours d'exécution (les résultats ne sont disponibles qu'après la fin) et obtenir les résultats du test (nous avons choisi le format JSON)
var yui_instance; //the YUI instance
var runner; //The YAHOO.Test.Runner
var Assert; //an instance of YAHOO.Test.Assert to save coding
var testSuite; //The YAHOO.Test.Suite that will get run.
/**
* Sets the required value for the name property on the given template, creates
* and returns a new YUI Test.Case object.
*
* @param template the template object containing all of the tests
*/
function setupTestCase(template) {
template.name = "jsTestCase";
var test_case = new yui_instance.Test.Case(template);
return test_case;
}
/**
* Sets up the test suite with a single test case using the given
* template.
*
* @param template the template object containing all of the tests
*/
function setupTestSuite(template) {
var test_case = setupTestCase(template);
testSuite = new yui_instance.Test.Suite("Bond JS Test Suite");
testSuite.add(test_case);
}
/**
* Runs the YAHOO.Test.Suite
*/
function runTestSuite() {
runner = yui_instance.Test.Runner;
Assert = yui_instance.Assert;
runner.clear();
runner.add(testSuite);
runner.run();
}
/**
* Used to see if the YAHOO.Test.Runner is still running. The
* test results are not available until it is done running.
*/
function isRunning() {
return runner.isRunning();
}
/**
* Gets the results from the YAHOO.Test.Runner
*/
function getTestResults() {
return runner.getResults(yui_instance.Test.Format.JSON);
}
En ce qui concerne le côté sélénium, nous avons utilisé un test paramétré. Nous exécutons nos tests dans les deux IE et FireFox dans la méthode de données, en analysant les résultats du test dans une liste de tableaux d'objets avec chaque tableau contenant le nom du navigateur, le nom du fichier de test, le nom du test, le résultat (réussir, échouer ou ignorer) et le message.
Le test réel ne fait qu'affirmer le résultat du test. S'il n'est pas égal à "réussite", il échoue au test avec le message renvoyé par le résultat du test YUI.
@Parameters
public static List<Object[]> data() throws Exception {
yui_test_codebase = "file:///c://myapppath/yui/tests";
List<Object[]> testResults = new ArrayList<Object[]>();
pageNames = new ArrayList<String>();
pageNames.add("yuiTest1.html");
pageNames.add("yuiTest2.html");
testResults.addAll(runJSTestsInBrowser(IE_NOPROXY));
testResults.addAll(runJSTestsInBrowser(FIREFOX));
return testResults;
}
/**
* Creates a Selenium instance for the given browser, and runs each
* YUI Test page.
*
* @param aBrowser
* @return
*/
private static List<Object[]> runJSTestsInBrowser(Browser aBrowser) {
String yui_test_codebase = "file:///c://myapppath/yui/tests/";
String browser_bot = "this.browserbot.getCurrentWindow()"
List<Object[]> testResults = new ArrayList<Object[]>();
Selenium = new DefaultSelenium(APPLICATION_SERVER, REMOTE_CONTROL_PORT, aBrowser.getCommand(), yui_test_codebase);
try {
Selenium.start();
/*
* Run the test here
*/
for (String page_name : pageNames) {
Selenium.open(yui_test_codebase + page_name);
//Wait for the YAHOO instance to be available
Selenium.waitForCondition(browser_bot + ".yui_instance != undefined", "10000");
Selenium.getEval("dom=runYUITestSuite(" + browser_bot + ")");
//Output from the tests is not available until
//the YAHOO.Test.Runner is done running the suite
Selenium.waitForCondition("!" + browser_bot + ".isRunning()", "10000");
String output = Selenium.getEval("dom=getYUITestResults(" + browser_bot + ")");
JSONObject results = JSONObject.fromObject(output);
JSONObject test_case = results.getJSONObject("jsTestCase");
JSONArray testCasePropertyNames = test_case.names();
Iterator itr = testCasePropertyNames.iterator();
/*
* From the output, build an array with the following:
* Test file
* Test name
* status (result)
* message
*/
while(itr.hasNext()) {
String name = (String)itr.next();
if(name.startsWith("test")) {
JSONObject testResult = test_case.getJSONObject(name);
String test_name = testResult.getString("name");
String test_result = testResult.getString("result");
String test_message = testResult.getString("message");
Object[] testResultObject = {aBrowser.getCommand(), page_name, test_name, test_result, test_message};
testResults.add(testResultObject);
}
}
}
} finally {
//if an exception is thrown, this will guarantee that the Selenium instance
//is shut down properly
Selenium.stop();
Selenium = null;
}
return testResults;
}
/**
* Inspects each test result and fails if the testResult was not "pass"
*/
@Test
public void inspectTestResults() {
if(!this.testResult.equalsIgnoreCase("pass")) {
fail(String.format(MESSAGE_FORMAT, this.browser, this.pageName, this.testName, this.message));
}
}
J'espère que ceci est utile.
J'ai regardé la date de votre question et à l'époque il y avait quelques bons lib/framework de test JS. Aujourd'hui, vous pouvez trouver beaucoup plus et dans différents domaines tels que TDD, BDD, Assetion et avec/sans support des coureurs.
Il y a beaucoup de joueurs dans ce jeu comme Mocha, Chai, QUnit, Jasmine, etc ... Vous pouvez trouver plus d'informations dans this blog sur JS/Mobile/web testing ...
Il y a un nouveau projet qui vous permet d'exécuter des tests qunit dans un environnement Java (comme ant) afin que vous puissiez intégrer pleinement votre suite de tests côté client avec vos autres tests unitaires) .
http://qunit-test-runner.googlecode.com
Je l'ai utilisé pour tester les plugins jQuery, objx code, personnalisé OO JavaScript et cela fonctionne pour tout sans modification.
J'ai publié un petite bibliothèque pour vérifier les tests JavaScript dépendants du navigateur sans avoir à utiliser un navigateur. Il s'agit d'un module node.js qui utilise zombie.js pour charger la page de test et inspecter les résultats. J'ai écrit à ce sujet sur mon blog . Voici à quoi ressemble l'automatisation:
var browsertest = require('../browsertest.js').browsertest;
describe('browser tests', function () {
it('should properly report the result of a mocha test page', function (done) {
browsertest({
url: "file:///home/liam/work/browser-js-testing/tests.html",
callback: function() {
done();
}
});
});
});
Le projet sur lequel je travaille utilise Js-Test-Driver hébergement Jasmine on Chrome 10 avec Jasmine-JSTD- Adapter y compris l'utilisation de Couverture du code tests inclus dans JS-Test-Driver. Bien qu'il y ait des problèmes à chaque fois que nous modifions ou mettons à jour les navigateurs sur environnement CI le les tests jasmine fonctionnent assez bien avec seulement des problèmes mineurs avec les tests ansynchrones, mais pour autant que je sache, ceux-ci peuvent être contournés en utilisant Jasmine Clock mais je n'ai pas encore eu la chance de les corriger.
Un autre framework de test JS qui peut être exécuté avec Ant est CrossCheck . Il y a un exemple d'exécution de CrossCheck via Ant dans le fichier de construction du projet.
CrossCheck tente, avec un succès limité, d'émuler un navigateur, y compris des implémentations de style simulé de XMLHttpRequest et timeout/interval.
Cependant, il ne gère pas actuellement le chargement de javascript à partir d'une page Web. Vous devez spécifier les fichiers javascript que vous souhaitez charger et tester. Si vous gardez tous vos JS séparés de votre HTML, cela pourrait fonctionner pour vous.
Il s'agit d'une bonne évaluation de plusieurs outils de test.
Outils de test unitaire JavaScript pour TDD
Personnellement, je préfère https://code.google.com/p/js-test-driver/
J'ai écrit une tâche Ant qui utilise Phantom JS , un navigateur webkit sans tête, pour exécuter des fichiers de test html QUnit dans un processus de génération Ant. Il peut également échouer la génération si des tests échouent.