27 votes

Développement piloté par les tests de frontends Web JavaScript

Cela peut sembler un peu idiot, mais je suis un peu confus comment l'approche de test JavaScript pour les interfaces web. Pour autant que je suis concerné, typique de l'architecture 3 tier ressemble à ceci:

  1. Niveau de base de données
  2. Le niveau d'Application
  3. Niveau Client

1 est d'aucun intérêt dans cette question. 2 contient toute la logique du programme ("logique d'entreprise") 3 le frontend.

Je ne test-driven development pour la plupart des projets, mais seulement pour l'application de la logique, de ne pas le frontend. C'est parce que les tests de l'INTERFACE utilisateur est difficile et inhabituelle en TDD, et, normalement, ne se fait pas. Au lieu de cela, toute la logique de l'application est séparée de l'INTERFACE utilisateur, de sorte qu'il est simple de tester cette logique.

L'architecture à trois niveaux soutient ceci: je peux concevoir mon backend comme une API REST qui est appelée par mon frontend. Comment JS tests d'ajustement dans? Pour le type à trois niveaux de l'architecture en JS (c'est à dire JS sur le client), l'expérimentation n'a pas beaucoup de sens, n'est ce pas?

Mise à jour: J'ai changé la question de la formulation de "Test de JavaScript dans les interfaces web de" de "développement piloté par les tests de JavaScript interfaces web" pour préciser ma question.

18voto

G-Wiz Points 4800

Rappelez-vous ce qui est le point de test unitaire est: la garantie d'un module particulier de code réagit à certains stimuli attendu. En JS, une partie importante de votre code, (sauf si vous avez quelques cadre du cycle de vie comme le Sencha ou YUI) sera directement manipulation du DOM ou de faire des appels à distance. Pour tester ces choses, vous appliquez simplement traditionnelle de l'unité de techniques de dépistage de l'injection de dépendance et se moquant/buter. Cela signifie que vous devez écrire chaque fonction ou de la classe, que vous voulez des tests unitaires pour accepter se moque de la structure dépendante.

jQuery prend en charge ce en vous permettant de passer d'un document XML dans toute la traversée de fonctions. Alors que vous pourriez écrire normalement

$(function() { $('.bright').css('color','yellow'); }

vous aurez plutôt envie d'écrire

function processBright(scope) {
    // jQuery will do the following line automatically, but for sake of clarity:
    scope = scope || window.document;

    $('.bright',scope).css('color','yellow');
}

$(processBright);

Avis nous n'avons pas seulement tirer la logique de la fonction anonyme et lui donner un nom, nous faisons aussi que la fonction accepte un paramètre d'étendue. Lorsque cette valeur est null, le jQuery, les appels continuent de fonctionner normalement. Cependant, nous avons maintenant un vecteur pour l'injection d'un simulacre de document que l'on peut inspecter une fois que la fonction est appelée. L'unité de test pourrait ressembler à

function shouldSetColorYellowIfClassBright() {
    // arrange
    var testDoc = 
        $('<html><body><span id="a" class="bright">test</span></body></html>');

    // act
    processBright(testDoc);

    // assert
    if (testDoc.find('#a').css('color') != 'bright')
        throw TestFailed("Color property was not changed correctly.");
}

TestFailed pourrait ressembler à ceci:

function TestFailed(message) {
    this.message = message;
    this.name = "TestFailed";
}

La situation est similaire avec les appels distants, mais plutôt que l'injection de certains de facilité, vous pourriez vous en sortir avec un masque de stub. Disons que vous disposez de cette fonction:

function makeRemoteCall(data, callback) {
    if (data.property == 'ok') 
        $.getJSON({url:'/someResource.json',callback:callback});
}

Vous pouvez tester en tant que tel:

// test suite setup
var getJSON = $.getJSON;
var stubCalls = [];
$.getJSON = function(args) {
    stubCalls[stubCalls.length] = args.url;
}

// unit test 1
function shouldMakeRemoteCallWithOkProperty() {
    // arrange
    var arg = { property: 'ok' };

    // act
    makeRemoteCall(arg);

    // assert
    if (stubCalls.length != 1 || stubCalls[0] != '/someResource.json')
        throw TestFailed("someResource.json was not requested once and only once.");
}

// unit test 2
function shouldNotMakeRemoteCallWithoutOkProperty() {
    // arrange
    var arg = { property: 'foobar' };

    // act
    makeRemoteCall(arg);

    // assert
    if (stubCalls.length != 0)
        throw TestFailed(stubCalls[0] + " was called unexpectedly.");
}

// test suite teardown
$.getJSON = getJSON;

(Vous pouvez emballer tout ça dans le module de modèle à pas de la litière de l'espace de noms global.)

Pour appliquer tout cela dans un test-driven manière, vous pouvez tout simplement écrire ces premiers essais. C'est simple, sans fioritures, et surtout, de manière efficace de tests unitaires JS.

Des cadres comme qUnit peut être utilisé pour piloter votre appareil-tests, mais c'est seulement une petite partie du problème. Votre code doit être écrit dans un essai de manière conviviale. Aussi, les cadres comme le Sélénium, l'interface htmlunit, jsTestDriver ou Watir/N sont pour les tests d'intégration, pas de tests unitaires en soi. Enfin, en aucun cas votre code orienté objet. Les principes de tests unitaires sont facilement confondus avec ceux de l'application pratique des tests unitaires dans un système orienté objet. Ils sont séparés mais compatible idées.

Les Tests De Styles

Il est à noter que deux de test différents styles sont illustrés ici. La première suppose une ignorance complète de la mise en œuvre de processBright. Il pourrait être l'utilisation de jQuery pour ajouter de la couleur, de style, ou peut-être faire le natif de manipulation du DOM. Je suis contente de tester le comportement externe de la fonction est comme prévu. Dans la deuxième, je suppose la connaissance d'un interne de la dépendance de la fonction (à savoir $.getJSON), et ces tests couvrent la bonne interaction avec cette dépendance.

L'approche que vous prenez dépend de votre test de la philosophie et de l'ensemble des priorités et des coûts-avantages de profil de votre situation. Le premier test est relativement pur. Le deuxième test est simple, mais relativement fragile, si je change la mise en œuvre de makeRemoteCall, le test va se casser. De préférence, l'hypothèse que makeRemoteCall utilise $.getJSON est au moins justifiées par la documentation de makeRemoteCall. Il ya un couple de plus de discipline approches, mais un rapport coût-efficacité de l'approche consiste à envelopper les dépendances dans les fonctions wrapper. Le code de base dépendra uniquement sur ces wrappers, dont les implémentations peuvent être facilement remplacés par des bouts de test au test-temps.

3voto

sonicwizard Points 164

Il existe un livre intitulé Test-Driven JavaScript Development par Christian Johansen qui pourrait vous aider. Je n'ai regardé que certains des échantillons du livre (je viens de télécharger un échantillon sur Kindle l'autre jour), mais il ressemble à un excellent livre qui traite de ce problème. Vous pourriez le vérifier.

(Remarque: je n'ai aucun lien avec Christian Johansen et aucun investissement dans les ventes du livre. Cela ressemble à une bonne chose qui résout ce problème.)

2voto

Olegas Points 4787

J'ai un de même l'architecture de l'application avec JS niveau client. Dans mon cas, j'ai utiliser notre société JS-cadre pour mettre en œuvre niveau client.

Ce JS cadre est créé en programmation orientée objet, de style donc je peux mettre en œuvre des tests unitaires pour les classes de base et des composants. Aussi, afin de couvrir toutes les interactions de l'utilisateur (qui ne peuvent pas être couverts à l'aide de tests unitaires), je suis en utilisant Selenium WebDriver pour faire un test d'intégration du framework de composants visuels et les tester sous différents navigateurs.

Donc, TDD peut être appliquée à de développement JavaScript si le code testé est écrit dans la programmation orientée objet-manière. Aussi test d'intégration est également possible (et peut être utilisé pour faire une sorte de TDD).

1voto

line-o Points 510

Jetez également un œil à QUnit pour les tests unitaires des méthodes et fonctions JavaScript.

0voto

Gnat Points 1196

Vous pouvez tester votre application à partir d'un point de vue utilisateur avec des outils tels que Rational functional tester, les outils HP ou d'autres logiciels équivalents.

Ces outils de test de l'application comme si l'utilisateur était assis en face d'elle, mais de manière automatisée. Cela signifie que vous pouvez tester toutes les trois niveaux en même temps, et surtout le Javascript qui peut être difficile à tester autrement. Les tests fonctionnels comme ceci peut vous aider à trouver les bugs de l'INTERFACE utilisateur et les imperfections avec la façon dont l'INTERFACE utilisateur est en utilisant les données de la pression de votre niveau intermédiaire.

Malheureusement, ces outils sont très cher, alors il y a peut être d'autres équivalents (et je serais intéressé de savoir de ces outils).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X