outils de tests d'interface - fil lille 1bilasco/oti/oti2016a.pdf · 3 tests dans un cadre...
TRANSCRIPT
1
Outils de Tests d'Interface
a) Plateformes de tests : JUnit, PHPUnit, Qunit
b) Outils de qualité : sonar
c) Selenium
d) Outils de déploiement : maven
http://www.fil.univ-lille1.fr/~bilasco/OTI/OTI2016a.pdf
2
Tests
● Les tests assurent
– qualité du code : fiable, robuste
– tests de régression fréquents
– retour d'expérience rapide
– identification des problèmes rares et/ou non testé manuellement
– documentation : exemples fonctionnels
● A quel prix ? Quand est-ce qu'on en écrit ?
● Séparation entre code tests et code métier
– code défi ni, développé et livré séparément des tests● src/ vs test/
3
Tests
Dans un cadre collaboratif code écrit 1 fois, répliqué n fois
Dans un cadre Agile itérations courtes, documentées par les tests
eXtreme Programming (XP) / Test Driven Development développer les tests unitaires en même temps/avant le
programme à tester à partir des spécifi cations on n'écrit que le code nécessaire à valider les tests
… en TP ?
4
Tests
Qu'est-ce … et comment écrire des Tests unitaires ?http://fr.wikipedia.org/wiki/Test_%28informatique%29http://fr.wikipedia.org/wiki/Test_unitairehttp://portail.fi l.univ-lille1.fr/portail/index.php?dipl=MInfo&sem=S8&ue=SVL
Tests pour les applications connectées
Code métier
BD
Interface & Interactions
Code
T. Interface
T. Métier T. Métier
5
● Outils pour tests unitaires : – JUnit 4.0– PHPUnit, SimpleTest– QUnit JS, Jasmine, Buster.JS, jstestdriver ...
● Outils pour tests interface utilisateur : – Selenium
● Exercices (rendus à la fi n de séances / module)● Evaluations
– Couverture de tests pour les codes WebA/FwkJS
6
Organisation générique des tests
Code
- classes- méthodes
Ou
- modules- fonctions/procédures
Test Case A
- tests - par fonctionnalités
- par méthode/fonction- par contexte d'usage
AssertionsEchecs
Test Case B
- tests - par fonctionnalités
- par méthode/fonction- par contexte d'usage
AssertionsEchecs
Test suite
7
Un Cas de Test - Principe général
● Hypothèse
– configuration de l'état de départ du système● Actions (testées)
– transformation sur l'état du système● Résultat attendu
– vérification de l'état attendu (assert)
– production d'une exception
8
Tests – JUnitorg.junit.* (JUnit 4.0)
Interface : Test
Classes : (J4.0) Toute classe contenant @org.junit.Test
(J4.0) @org.junit.runners.Suite
Assert (méthodes assertXXX() et failZZZ()) - JSONAssert de net.sf.json.tests → asserts pour JSONObject, JSONArray
Méthodes
@Test or @Test(expected=Exc.class) void yyy() {...} (Test.)assertXXX(...) - True, False, Equal @Before{Class} – init. des objets auxiliaires par test/classe
@After{Class} - relâche les objets auxiliaires @Suite.SuiteClasses({ MyT.class })
9
Exemple JUnit 4.x - Assert
import org.junit.*;
public class MoneyTest { //Construire un nouveau test case
private Money f12EUR, f14EUR;
@BeforeClass /* or Before – each Test */
protected void init() { //Construction de objets tests
f12EUR = new Money(12,"EUR");
f14EUR = new Money(14,"EUR");
}
@Test
public void simpleAdd () { //Une des méthodes de test
Money expected = new Money(26,"EUR");
Money result= f12EUR.add(f14EUR);
assertTrue(expected.equals(result));
}
} .
10
Exemple JUnit 4.x - Exception
import org.junit.*;
public class MoneyTest { //Construire un nouveau test case
private Money f12EUR, f14EUR;
@BeforeClass /* or Before – each Test */
protected void init() { //Construction de objets tests
f12EUR = new Money(12,"EUR");
f14EUR = new Money(14,"EUR");
}
@Test(expected=SubImpossibleException.class,timeout=msTimeoutValue)
public void simpleSubImpossible () { //Une des méthodes de test
Money result= f12EUR.sub(f14EUR);
}
} .
11
Suites de tests - JUnit
Organiser/Composer/Regrouper plusieurs Tests JU 3.8 : TestSuite TestSuite suite = new TestSuite("MoneyTestSuite"); suite.addTestSuite(MoneyTest.class); //ajout de tous les tests suite.addTest(new AnotherMoneyTest("testOtherMoneyMethodName");
//ajout de tests spécifi ques JU 4.0 : Suite @RunWith(Suite.class) @SuiteClasses({MoneyTest.class,AnotherMoneyTest.class})
class AllTests {} ;;
RepeatedTest (JU3.8) Performance ou erreur intermittente suite.addTest(new RepeatedTest(new MoneyTest("testSimpleAdd"),100)); suite.addTest(new RepeatedTest(new MoneyTest("testComplexAdd"),100));
12
JUnit Exercices
● http://forge.fil.univ-lille1.fr/OTI/wiki/JUnitExo
● http://forge.fil.univ-lille1.fr/OTI/wiki/JUnit4Exo
MoneyFactory.class
::+getDefaultFactory+createMoney
Money.class
- Money+getValue +getCurrency
+toString
MoneyOps.class
:: +simpleAdd
IncompatibleCurrenciesException.class
UnexistingCurrencyException.class
MoneyAddTestCase.class
+testSimpleAdd
MoneySameCurrTest.class
+testSame+testNotSame
MoneyEqTest.class
+testMemeValeurMemeDevise+testMemeValeurDeviseDifff//
13
JUnit et Mock
● Maîtriser le comportement des objets accessoires inclus dans un test unitaire → isoler le comportement à tester
● Disposer des objets à comportement contrôlé
14
JUnit et Mock (2)
● Automatiser la construction des objets dont le comportement est contrôlé tout en préservant les interfaces logicielles
– renvoie en dur des valeurs pour les méthodes invoquées(STUB)
● Observer le comportement des objets contrôlés (appel de méthode, …)
– vérifier l'utilisation qui en est faite après exécution(SPY)
● … tout en assurant de la transparence d'un point de vue usage : objet et mock ont la même signature
● D'autres utilisations
– Des classes partiellement implémentées
– Disponibilités de ressources limitées (appels WS, BD)
– Etat de systèmes difficilement reproductible in vivo
15
JUnit et Mockito.org (3)
X
X
● Créer un mock (stub) à partir d'une interface/class
– Interface obj_mock=mock(Interface.class)
– Pas d'état interne → variables membres non initialisées / méthodes vides
– Remplacer (partiellement) le comportement par défaut● doReturn().when(obj_mock).methode() ou
when(obj_mock.methode()).thenReturn()
● Créer un mock (stub) à partir d'une interface/class
– Interface obj_mock=mock(Interface.class)
– Pas d'état interne → variables membres non initialisées / méthodes vides
– Remplacer (partiellement) le comportement par défaut● doReturn().when(obj_mock).methode() ou
when(obj_mock.methode()).thenReturn()● sauf pour hashCode(),equals() ou méthodes private/final
16
JUnit et Mockito (3)
● Créer un mock (stub) à partir d'une interface/class
– Interface obj_mock=mock(Interface.class)
– Pas d'état interne → variables membres non initialisées
– Remplacer (partiellement) le comportement par défaut
● doReturn().when(obj_mock).methode() ou when(obj_mock.methode()).thenReturn()
● sauf pour hashCode(),equals() ou méthodes private/final
17
JUnit et Mockito (4)
● Créer un mock partiel (spy) à partir d'un objet
– Interface obj_spy=spy(new Classe())
– état interne réel
– Remplacer (partiellement) le comportement par défaut
● doReturn().when(obj_spy).methode()
– Réaliser comportement par défaut, change juste le résultat
● when(obj_spy.methode()).thenReturn()
18
JUnit et Mockito (5)
● Créer un mock partiel (spy) à partir d'un objet
– Interface obj_spy=spy(new Classe())
– état interne réel
– Remplacer (partiellement) le comportement par défaut
● doReturn().when(obj_spy).methode()
– Réaliser comportement par défaut, change juste le résultat
● when(obj_spy.methode()).thenReturn()
– Permet de vérifier les appels réalisés sur un objet
● verify(obj_spy).methode() ou verify(obj_spy,times(N)).methode()
19
JUnit et Mockito (6)
● SimpleAdd example
● Re-écrire certains de vos tests en utilisant des mocks
● http://forge.fil.univ-lille1.fr/OTI/wiki/JUnitMockito
20
Outils de Tests d'Interface
a) Plateformes de tests : JUnit, PHPUnit, Qunit
b) Outils de qualité : sonar
c) Selenium
d) Outils de déploiement : maven
http://www.fil.univ-lille1.fr/~bilasco/OTI/OTI2016a.pdf
21
Tests Unitaires pour Javascript
● Une grande variété de plateformes de tests JS– http://en.wikipedia.org/w/index.php?title=List_of_unit_testing_frameworks§ion=32#JavaScript
● Restructurer votre code en vue de mettre en place de tests
– Séparer la partie fonctionnelle/métier ...
– … de la partie rendu (modification DOM, alertes, etc.)
– Organisez-le en fonctions indépendamment testables
– Un exemple de restructuration : http://qunitjs.com/intro/
22
Tests Unitaires pour Javascript
● Réfléchir à la séparation entre tests clients et tests serveurs
– Tests unitaire JS (client) vs Tests unitaires Java/PHPUnit (serveur)
Code métier
BD
Interface & Interactions
Code
T. Interface
T. Métier T. Métier
23
QUnit by JQueryhttp://code.jquery.com/qunit/qunit-qunit-2.0.1.css
http://code.jquery.com/qunit/qunit-2.0.1.js
● Tests et reports matérialisés dans des pages HTML
● TestCases
– Synchrones : QUnit.test (nom, funcDef)
– Asynchronnes : QUnit.test(nom, funcDef)
● assert.async() - bloquant / débloquant pour simuler l'attente
– Structurées: QUnit.module(nomMod, setup : funcDef, tearDown : funcDef)
● QUnit.module("suiteA", setup:function(){...}, teardown:function(){…})
QUnit.test("testA1", function() {...})
QUnit.test("testA2",function() {...})
● TestSuites (npm qunit-composite 2.0.0)
– QUnit.testSuites(["moduleA.html", "moduleB.html"]);
● Mocks (Sinon.JS - http://sinonjs.org/releases/sinon-qunit-1.0.0.js)
24
QUnit by JQueryhttp://code.jquery.com/qunit/qunit-2.0.1.csshttp://code.jquery.com/qunit/qunit-2.0.1.js
● Assertions
– assert – injecté comme dépendance dans le testQUnit.test("nom test",function(assert) {…}) ;
– assert.ok(param[,msg]) – test passé si paramètre param true
● assert.ok (1==1,"1 est tjs égal à 1") ;
– assert.[strict|deep}equal(result,expected[,msg]) – test passé si paramètres {strictement (type et valeur) / structurellement } égaux
● assert.strictEqual(1=="1","jamais ça marchera") ;● assert.equal(1=="1","la rigueur c'est pas pour nous") ;
– assert.throws(funcDef,expectedRegExp[,msg]) – test passé si expected lancée
● assert.throws(function(){throw "oups"},"oups","oups c'est passé")
– assert.expect(NbDAssertionsAttendues) ;
25
QUnit – test & throwsexemples
QUnit.test("test accesseurs", function(assert){ assert.expect(2) ;
var m=new money(1,"EUR");assert.ok(m.getValue()==1,"valeur = 1");assert.equal(m.getCurrency(),"EUR","currency = EUR");
});
QUnit.test("test simple ops", function(assert){ assert.expect(1) ; var m1=new money(1,"EUR"); var m2=new money(2,"EUR"); var m3=new money(3,"EUR"); assert.ok(m3.equals(MoneyOps.add(m1,m2)),"3e = 1e+2e");});
QUnit.test("test multi devise add", function(assert){
var m1=new money(1,"EUR"); var m2=new money(2,"CHF"); assert.throws(function() {var m3=MoneyOps.add(m1,m2)},
DevisesIncompatibleExc, "Devises Incompatibles");});
26
QUnit – tests and Ajax … the wrong way
QUnit.module("async");
QUnit.test("start",function(assert){ assert.ok(true); });
QUnit.test("connect using Ajax",function(assert){ var xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { assert.equal(xmlhttp.responseText,10); console.log("recieved "+xmlhttp.responseText); } } xmlhttp.open("GET","random.php",true); xmlhttp.send();});
Qunit.test("end",function(assert){assert.ok(true); });
<?phpsleep ( rand ( 2, 4));echo rand (9,11);?> random.php
http://www.fil.univ-lille1.fr/~bilasco/OTI/random_test_NS.htmlhttp://www.fil.univ-lille1.fr/~bilasco/OTI/random_test_NS.js
27
QUnit – tests and AjaxQUnit.module("async");
QUnit.test("start",function(assert){ assert.ok(true); });
QUnit.test("connect using Ajax",function(assert){ var done = assert.async() ;
var xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { assert.equal(xmlhttp.responseText,10); console.log("recieved "+xmlhttp.responseText);
done(); } } xmlhttp.open("GET","random.php",true); xmlhttp.send(); });
Qunit.test("end",function(assert){assert.ok(true); });
<?phpsleep ( rand ( 2, 4));echo rand (9,11);?> random.php
http://www.fil.univ-lille1.fr/~bilasco/OTI/random_test_NS2.htmlhttp://www.fil.univ-lille1.fr/~bilasco/OTI/random_test_NS2.js
28
QUnit by Jquery
● Page HTML de test QUnit
– inclusion de scripts src
– inclusion de scripts tests
● Résultats et données dans des divs prédéfinies
– id='qunit' – affichage des résultats
– id='qunit-fixture' – inclusion des éléments (champs, etc.) servant de support pour la réalisation des tests
● Utilise le trigger de jQuery pour simuler les interactions– .trigger( eventType [, extraParameters] )
29
Qunit - exemplequnit.js + qunit.css
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-2.0.1.css" /><script src="http://code.jquery.com/qunit/qunit-2.0.1.js"></script><script src="../src/money.js"></script><script src="../test/money_test.js"></script></head><body><div id="qunit"/><div id="qunit-fixture"/></body></html>
QUnit.module("money", {// setup:function(){alert("setup money");},// teardown:function(){alert("teardown money");}});
QUnit.test("test accesseurs", function(assert){
assert.expect(2) ;var m=new money(1,"EUR");assert.ok(m.getValue()==1,"valeur = 1");assert.equal(m.getCurrency(),"EUR","currency = EUR");
});
30
Test unitaires – Exos 1
● QUnit
● Commencer à réfléchir à comment mettre en place les tests sur vos codes WebA/FmwkJS
money.js
money(v,curr)getValue
getCurrrencyequals
money_ops.js
simpleAdd
money_exc.js
DevisesIncompatibleExc
money_test.js
constructoraccesseurs
equals
money_test.html
money_ops_test.js
simpleAddmultiDevise
money_ops_test.html
money_test_suite.js
money_test.htmlmoney_ops_test.html
money_test_suite.html
31
QUnit + SinonJShttp://sinonjs.org/qunit/
● Surveiller et Maîtriser le comportement des objets métiers JS
● Spy = surveiller le comportement (http://sinonjs.org/docs/#spies)
– anonyme : annon = sinon.spy() ou fonction : sinon.spy(obj, 'nom function')
– .calls / .args / .returnValues / .withArgs / .called{Once/Twice.../Before/After} / .calledWith
● Stub = Spy + contrôle sur les résultats (http://sinonjs.org/docs/#stubs)
– anonyme : annon = sinon.stub()
– fonction : sinon.stub(obj, 'nom function') ou sinon.stub(obj, 'nom', nvl_funct)
– object : sinon.stub(obj) ou sinon.createStubInstance(constructor)
– .withArgs / .onCall(n) / .returns / .throws / .restore
● Matchers sinon.match({1/ 'a' / '/^.*$/' /...) / sinon.match.{any/string/...}
● Assertions sinon.assert.*Called* sinon.assert.*Threw* ← incompatible avec QUnit2.0
● Fake Timers / XMLHttpRequest / Server
32
QUnit + SinonJShttp://sinonjs.org/qunit/support pour Qunit 2.0
● SinonJS conçu pour QUnit 1.x
● Changements QUnit1.x → 2.x https://qunitjs.com/upgrade-guide-2.x/
– 1.x : nombre d'assertions dans l'entête du test
– 1.x : test vs asynchTest
– 1.x : absence d'injection d'assert, ok,equal – globaux
● Adapter qunit-sinon1.0.0 → sinon-qunit 2.0.1
● ! Assertions sinonjs non-fonctionnelles : QUnit.ok → assert.ok
36
Test unitaires – Exos 2
● QUnit + SinonJS
● Commencer à réfléchir à comment mettre en place les tests sur vos codes WebA/FmwkJS
money.js
money(v,curr)getValue
getCurrrencyequals
money_ops.js
money(v,curr)getValue
getCurrrencyequals
money_exc.js
DevisesIncompatibleExc
money_test.js
constructoraccesseurs
equals
money_test.html
money_ops_test.js
simpleAddmultiDevise
money_ops_test.html
money_test_suite.js
money_test.htmlmoney_ops_test.html
money_test_suite.html
37
Retours
● « // throw new Exception » (this.d1 + " " + this.d2)
● « Le test c'est bien mais la console c'est mieux »– try { ... } catch (e) {console.log(e.toString());}
● «Ca y est, un test ca suffit »– var f=new factory(); ok(f.cur.length==2,"nb = 2"); equal(f.cur[0],"EUR","");
– var m1=f.create(1,"E") ; var m2=f.create(2,"E") ; equal(f.crees["E"]=3);
● «Un test en plus ne fait pas de mal »MoneyFactory.prototype.create = function (value, currency) { if (this.currencies.indexOf(currency.toUpperCase()) == -1) throw new Exc(); return new money( value, currency );}test("test create", function(){ throws(function() {var m = this.fact.create(1, "YEN")}, .., "Devise Inexistante"); throws(function() {var m = this.fact.create(-1, "EUR")}, ...,"Monnaie Négative");});
38
● « Je me fâche avec personne »– ok(m1.getValue()<"0","Negatif") ;
– If (v<0) alert 'Attention' ;
– default : this.moneyClass = mFactory.Euro;
● « Je suis généreux»– m1 = new Money(1, "EUR") ; m1.setValue(100) ;
● « Tant que j'utilise pas mes sous c'est pas grave »– this.curr=curr ; et puis test sur currency en Money_Ops
● « Egocentric »– throw new MonPropreEx
39
QUnit
● Tests sur le comportement métier des scripts
● Tests sur le comportement de l'interface
– changements dans le DOM
– apparition des alertes
40
QUnit et DOM
● Les tests s'exécutent au sein d'une page ← contexte DOM
● Isoler le contexte DOM associé dans le div id=qunit-fixtures
● Avant chaque tests construire les fixtures
– réfletant l'état du DOM suite aux actions de l'utilisateur var fixture=""; fixture+=("<div id='res'></div>"); fixture+=("<form id='form0'>"); fixture+=("<input type='text' id='v1' name='v1' value='2'/>"); fixture+=("<input type='text' id='c1' name='c1' value='EU'/>"); … var fixtureNode=document.getElementById("qunit-fixture"); fixtureNode.innerHTML=fixture; … c.computeResult(document.getElementById('form0'));
assert.equal(c.message,"...") ;
41
QUnit et (window.)alert
● Pas d'assertion spécifique pour traiter les alertes
● Redéfinir la fonction window.alert
● Garder une trace dans le div qunit-fixtures
...
42
Qunit+Sinon.JS+ (window.)alert
● Pas d'assertion spécifique pour traiter les alertes
● Intercepter la fonction window.alert
spy(window,"alert") ; ou stub(window,'alert') ;
● S'assurer qu'elle a été appellée
assert.ok(window.alert.calledOnce)
● Rétablir le comportement de window.alert
window.alert.restore()
...
43
Test unitaires – Exos 2
● QUnit et fixtures
index.html
div resform
calc.js
calc()computeResult(form)
displayResult(div)
calc_test.js
test computeResulttest outputResult
Utilisation de fixtures
var fixture="" ;fixture+="<div id='res'>.." ;fixture+="<form..>" ;fixture+="<input ..>" ;…document.getElementById
("qunit-fixture").innerHTML=fixture
44
Outils de Tests d'Interface
a) Plateformes de tests : JUnit, PHPUnit, Qunit
b) Outils de qualité : sonar
c) Selenium
d) Outils de déploiement : maven
http://www.fil.univ-lille1.fr/~bilasco/OTI/OTI2016a.pdf
45
SONAR
● Outil pour mesurer la qualité du code
46
SONAR
● Analyser le code (sonar-runner)
– Structure
– Convention de Codage
– Couverture et Tests
–
● Archivage des informations (sonarQube)
– Rapports
– Evolution de la qualité
–
● Solution générique
– plugins par langage et par fonctionnalité
SonarQube
R1 R2
sonar runner
plugins
outils externes
47
Sonar et JS
● Plugin SonarQube Javascript disponible
– n'extrait pas directement les données de couverture de tests
● Exécuter les tests JS en ligne de commande + récupérer résultats
– utiliser Karma (npm)
– serveur prenant la main sur un ou plusieurs navigateurs
– configuration du projet (karma.conf.js)
● Récupération des informations de « coverage » ( + Karma-coverage)
● Alimenter SonarQube en utilisant sonar-runner
48
Sonar et JS
● Configuration Karma
– node_modules/karma-cli/bin/karma init karma.conf.js– choix framework/browser/sources+tests/ignore_files
● Récupération des informations de « coverage » ( + Karma-coverage)
– pré-processing
● preprocessors: {'src/*.js':['coverage']}
– reporting
● reporters: ['progress','coverage','junit'],coverageReporter: {type: 'lcov', dir: 'reports', subdir: 'coverage'}
● Lier reporting Karma à la configuration Sonar
– sonar.javascript.lcov.reportPath=reports/coverage/lcov.info
49
Sonar - exercices
● Travail sur le projet Money_JS
– Installer SonarQube
– Configurer sonar-project.properties (runner->qube)
– Lancer Analyse
– Installer Karma + coverage
● karma qunitjs karma-qunit karma-phantomjs-launcher● karma-coverage
– Configurer karma.conf.js
– Lancer Analyser / Récupérer informations sur les tests
– Faire évoluer votre code
– Re-lancer l'analyser
50
Sonar - exercices
● Travail sur le projet Money_Java
– Installer SonarQube
– Configurer sonar-project.properties (runner->qube)
– Lancer Analyse
– Configurer Maven
– Lancer Analyser / Récupérer informations sur les tests
– Faire évoluer votre code
– Re-lancer l'analyseur
51
Selenium – Tests UIhttp://seleniumhq.org/docs/
● Selenium automates browsers.
● Initialement conçu pour réaliser des tests dans les applis Web
– Interaction à travers les pages d'un navigateur
– Clique/Ecrit/Valide/Interagit/Constate à ma place● Construire des macros visuels pour la maintenance
● Formalisme pour décrire les actions simulées
● Formalisme pour constater/mésuser les effets des actions
– sur la page (modifications du DOM)
– ou dans l'interaction (alertes ...)
52
Selenium – une famille de solutions
● Selenium IDE
– Plugin navigateur pour enregistrer/exécuter les scénarios de tests
– Création des tests rapides
– Reproduire des bugs
– Absence de logs, metrics
● Selenium WebDriver
– Tests robustes en vue d'automatiser l'étude de la régression
– Passage à l’échelle des tests
– Clients en Java, C#, Python, Ruby, PHP, Javascript
53
Selenium IDE Commandes (ou Selenese)
● Enregistrer des Actions
– Ouvrir une page (open)
– Saisir un texte (type)
– Cliquer (click*)
– Choisir options (select*)
● Accessors pour le contenu
● Assertions des effets sur
– le contenu du document
– les propriétés des éléments
– les fenêtres du navigateur
● 1 Script = actions + assertions
54
Selenium IDE – Commandes et suites
● Une commande selenese est composée de :
– Action : ensemble prédéfini des types de commandes
– Locator : comment identifier/référencer l'élément concerné
● id, xpath, css
– Value : paramètre de la commande
● Un encodage HTML pour l'instant
● Assembler les commandes dans un test case (.html)
– <table> dont les lignes sont des commandes
– <tr> commande et <td> éléments de la commande● Assembler les tests cases en tests suite
– <table> dont les lignes sont des liens vers tests cases
55
Selenium UI – Référencement des élémentsLocators
● Référencer les éléments concernées par les actions
● Par id: id = elementID (attribut id requis sur les éléments à référencer)● Par name: name = elementNom (attribut name requis)● Par identifier: identifier=formNOMouID (par id et puis par name)● Par XPath: xpath=/html/body/form0/input[3], xpath=//form/input[@id='x']● Par link: link=Texte_Entre_<A>_et_</A>● Par DOM: dom=document.getElementById('myForm')● Par CSS: css=#loginForm input[type="button"] (4)
● Adaptez vous à la nature du document testé
● Choisissez des références robustes aux changements dans la page – limitez les contraintes de localisation dans le code
56
Selenium UI – Actionshttp://release.seleniumhq.org/selenium-core/1.0/reference.html#actions
● Interactions
– Souris : {double/}click{/At}, mouseMove{/At}, dragAndDrop{/ToObject} ...
– Clavier : keyPressed,{alt/control}Key{Up/Down}, type …
● Formulaires : select(selectLocator,labelLocator)
● Fenêtres et PopUp
– Ouverture: openWindow, select{Window,Frame,PopUp}
– Interaction: choose{Cancel/OK}OnNextConfirmation, deselectPopUp
● Scripts : addScripts
● Interactions+temps d'arrêt pour rechargement : XXXAndWait
– À éviter en présence d'AJAX
<tr><td>clickAndWait</td><td>id=nextPageBtn</td><td></td></tr>
57
Selenium UI - Actions
● Stockage et Variables
– storeXXX{/Present/NotPresent}, storeEval
<tr><td>storeText</td><td>id=login</td><td>lg</td></tr>
<tr><td>storeEval</td><td>storedVars['lg'].toUpperCase()</td><td>M</td></tr>
● Validation
– assertXXX{/Present/NotPresent} → le test s'arrête définitivement
– verifyXXX → test continue, notification de l'échec
– waitForXXX → le script attend qu'un état soit observé (support AJAX)
58
Selenium UI - Exemple
Addition Test
open ~bilasco/MoneyMoneyMoney/index.php
type name=v1 12
type name=c1 EUR
type name=v2 12
type name=c2 EUR
clickAndWait css=input[type="submit"]
assertText id=ops ADD
assertText id=result_detail (EUR) 24
v1
v2
d1
d2
ops
result_detail
59
Selenium WebDriver
● Construire de tests d'intégration automatisé à base d'API
– s'abstraire d'un navigateur spécifique
– automatiser exécution
– structures de contrôle
● Navigateurs supportés
– Safari, InternetExplorer, Firefox, Opera, Chrome
● Dispositifs d'accès
– Desktop, Android, Iphone
● API décliné en
– java, c#, python, ruby, php, perl, javascript
60
Selenium TestsAPI.java
SeleniumWeb Driver
server
Android Chrome Firefox
Actions Créer WebDriverExécuter Selenesse
InformerSignaler
Selenium TestsAPI.php
Selenium TestsAPI.js
RemoteWebDrivers
61
Selenium WebDriver – APIorg.openqa.selenium.*
● Navigateur générique : RemoteWebDriver
● Navigateur spécifique : selenium.{nomnavigateur}
– classes spécifiques pour interaction avec navigateur spécifique
● Interactions simples et complexes : selenium.interactions
– ClickAction,ClickAndHold,ContextClick,DoubleClick,...
– KeyDownAction,KeyUpAction,SendKeys
– touch.*
– CompositeAction
● Localisation des élements : Interface Locators
– selenium.internals
● FindsBy{ClassName,CssSelector,Id,LinkText,Name,TagName,XPath}
●
62
Selenium Web Driver - RemoteWebDriver
● Capabilities – un sac de CapabilityType
– startSession(Capabilities)/stopSession() ● Chargement page : get(String adresseWeb)
● Naviguer navigate()
– back(),forward(),refresh(),to()
– switchTo().{alert(),frame(name),window(name)}● Executer scripts
– execute{Async}Script(String script, Object... args)
● Contrôle de la souris/clavier getKeyboard()/getMouse()
63
Selenium Web Driver - RemoteWebDriver
● Localiser : findElement(s){ByClassName,...}(Object cle)
– les WebElement sont contrôlables
– By.xpath, By.id, By.tagName, By.name …
64
Selenium Web Driver - {Remote}WebElement
● Etat du WebElement
– isEnabled(),isSelected(),isDisplayed()
– getSize(),getLocation(),getText(),getAttribute()
– findElement()
● Interactions simples à partir du WebElement
– welt.sendKeys(), welt.click(), welt.submit()
● Interactions complexes avec interactions.Actions
– construire une suite d'actions new Actions(driver)
– ajouter this.keyDown(Keys.CONTROL).click(welt1).keyUp(welt2).
– executer this.build().perfom()
● Interagir avec les options d'un select dans un formulaire : Select(WebElement)
65
Selenium WebDriveTemps d'arrêt (...AndWait)
● Navigation entre pages / Rechargement de pages / AJAX
● Combien de temps attendre avant de poursuivre?
● Observer un changement
– Apparition/Disparition d'un élément sur la page
– Changement d'état sur un élément existant
– Alertes
66
Selenium WebDriveTemps d'arrêt (...AndWait)
● Objets marquant les temps d'arrêt : WebDriveWait
WebDriverWait wdwait = new WebDriverWait(driver, timeout);
● Continuer à condition que …
wdwait.until(ExpectedCondition)
● Collections de conditions prédéfinies ExpectedConditions
– [in]visibilityOf(WebElt.)/[in]visibilityofElementLocated(By l) ...
wdwait.until(ExpectedConditions.alertsPresent());
wdwait.until(ExpectedConditions.presenceOfElementLocated(By.id("v1")))
● Definir ses propres ExpectedCondition
– surcharger la methode apply(WebDriver d)
67
Selenium WebDriveTemps d'arrêt (...AndWait) - Exemple
● Utilisation d'une condition prédéfinie
● Création d'une condition
new WebDriverWait(driver,10,500). until(ExpectedConditions.
visibilityOfElementLocated(By.id("result"))
;
new WebDriverWait(driver,10,500). until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {return d.findElement(By.id("result")).isDisplayed() ;
} }
68
Selenium UI - Exemplev1
v2
c1
c2
ops
result_detail
@Before public void createDriver() {driver = new FirefoxDriver();}@Test public void test() { driver.get("http://localhost/~bilasco/Money/index.php"); WebElement element = driver.findElement(By.name("v1"));
element.sendKeys("12"); … ;element.submit(); new WebDriverWait(driver, 10).until(ExpectedConditions.
visibilityOfLocatedElement(By.id("result_detail"))); assertEquals(driver.findElement(By.id("result_detail")).getText(),
"(EUR) 24")) ; }@After public void releaseDriver() {driver.quit()} ;
69
Exercices
● Exercices sur Wiki– http://forge.fil.univ-lille1.fr/OTI/wiki/TestsSelenium
– http://forge.fil.univ-lille1.fr/OTI/wiki/TestsSeleniumWebDriver
● Travailler sur les tests pour vos codes JavaScript (WebA ou FmwkJS)
70
Outils de Tests d'Interface
a) Plateformes de tests : JUnit, PHPUnit, Qunit
b) Selenium
c) Outils de déploiement : maven
d) Outils de qualité : sonar
http://www.fil.univ-lille1.fr/~bilasco/OTI/OTI2016a.pdf
71
Systèmes de déploiement
(GNU) MakeCompilation & dépendances
(Apache) AntCompilation & dépendances & tâches
(Apache) MavenDépendances symboliques
Structuration des projets en familles
Automatisation
Plugins dédiés pour :
distribution : Jar, Ear, War, Aar
tests : surfire
sonar : sonar
scv : maven-scm-plugin
72
Maven
●Proposer un système de build universel
●Un cadre type pour la construction de projet
●Organiser les projets de manière hierarchique ● GroupID/ArtifactID/Version● Réutilisation à tout prix● Héritage entre projets
●Aider dans la gestion des distributions et suivi de bugs●Management de distributions – intégration SCM ●Management de dépendances
73
Maven
●Proposer un système de build universel
●Un cadre type pour la construction de projet
●Organiser les projets de manière hierarchique ● GroupID/ArtifactID/Version● Réutilisation à tout prix● Héritage entre projets
●Aider dans la gestion des distributions et suivi de bugs●Management de distributions – intégration SCM ●Management de dépendances
74
Maven – fonctionnalités
Proposer des lignes de conduites pour un développement optimal
Structure de projets prédéfinie
Séparation entre sources (main) et tests (test)
- src/ - main/
- java/ - ressources/ - config/ - test/ ...
- target/ ...- pom.xml
75
Maven - POM
POM ou "Project Object Model"● Représentation XML pour les projets Maven
Un project (Maven) ou archetype contient ● Identification du projet● fichiers de configuration ● développeurs intervenant dans le projet● l'organisation et les licences ● l'URL où est visible le projet ● les dépendances du projet ● les plugins
– SCV, Tests, Système de traçage de bugs ...
76
Maven – POM
<project xmlns="http://maven.apache.org/POM/4.0.0"...> <modelVersion>4.0.0</...>
<!-- The Basics -->
<groupId>...</...> <version>...</...> <packaging>...</...> <dependencies>...</...>
<parent>...</...> <dependencyManagement> … </...> <modules>...</...> <packaging>...</...>
<!-- Build Settings -->
<build>...</build> <reporting>...</reporting>
<!-- More Project Information -->
<name>...</...> <url>...</...> <licenses>...</...> <developers>...</...> <contributors>...</...>
<!-- Environment Settings -->
<mailingLists>...</...> <scm>...</...> <prerequisites>...</...> <repositories>...</...>
<pluginRepositories>...</...> <distributionManagement>...</...> ...
</project>
77
Maven – cycle de vie
78
Maven - cycle de vie
mvn archetype:generate – construction POM + dossiers
mvn validate - POM correctement défini
mvn compile - compile les sources
mvn test - Lance les tests unitaires
mvn package - Prépare la distribution (J/W/Ear)
mvn verify - Tests de validation nv package.
mvn install - Installe le pk en local (dép. int.)
mvn deploy - Déploie le pk sur un serveur
79
Maven & Sonar - exercises
http://forge.fil.univ-lille1.fr/ODEVA/wiki/MavenExo
● Travail sur le projet JUnit
– Creation d'un projet Maven
– Compilation et Tests Unitaires
– Installer SonarQube
– Configurer sonar-project.properties (runner->qube)
– Lancer Analyse
– Faire évoluer votre code
– Re-analyser
80
● … the end
● ...plus loin du contenu supplémentaire
81
Outils de Tests d'Interface
a) Plateformes de tests : JUnit, PHPUnit, Qunit
b) Outils de qualité : sonar
c) Selenium
d) Outils de déploiement : maven
http://www.fil.univ-lille1.fr/~bilasco/OTI/OTI2016a.pdf
82
PHPUnit
● Quasiment même concepts que JUnit
● Code test écrit et exécuté depuis le serveur
– phpunit.phar
● Intégré également dans frameworks (Symfony...)
● Classes de tests étendent
– PHPUnit_Framework_TestCaseclass TestCase1 extends PHPUnit_Framework_TestCase {...}
83
PHPUnit
● Initialisation – setUp{BeforeClass}, tearDown{BeforeClass}
● Asserts de langage – assert{InstanceOf,ClassHasAttribute,ObjectHasAttribute}
– assert{ArrayHasKey, Contains, Count}
– assertString{EndsWith,StartsWith}
● Exceptions – try {opsProduisantExc ; fail ("absence") ;} catch (Exc $e) {}
– $this->setExpectedException(excClassName,excMsg)
– /** * @expectedException Exc_Class_Name */
84
PHPUnit et les applis Web
● Asserts Sortie écran – setExpectedOutput{String/Regexp}
● Asserts orientés Web– XML : assert{EqualXMLStructure,XMLStringEqualsXMLFile,...}
– JSon : assertJsonFileEqualsJsonFile
– CSS : assertSelect{Count,Equals,Regexp}
– HTML : assertTag
● Extensions– PHPUnit/Extensions/Database/TestCase.php
85
PhpUnit
● Générateur de données (@dataProvider) pour simuler RepeatedTest
– function nomF() { return array(array(v1a,v1b),array(v2a,v2b),...)} ;
– /** @dataProvider nomF */ → fournit tableau de params.
– function testXXX($a,$b) {…}–
● Dépendances entres tests – ordonnancer les tests– /** @depends test1 */ function test2() { … }
Test1 * <----- Test2* mettre le système dans l'état attendu par Test2 – pas atomique
* les opérations autres que la cible du Test2 déjà validées
86
PHPUnit – Suite de tests
● Structurer les tests en répertoires– tests_dir
● test1.php● tests_dir2
– test2.php
– $ phpunit tests_dir
● … ou configurer phpunit.xml – <phpunit>– <testsuites>– <testsuite name="ts1">– <directory>Tests</directory>– <file>OtherTests/Test1.php</file>– <exclude>OtherTests/Test2.php</exclude>
– </testsuite>– </testsuites>– </phpunit>
87
PHPUnit Exercices
● http://forge.fil.univ-lille1.fr/OTI/wiki/PHPUnitExo
MoneyFactory.class.php
::+getDefaultFactory+createMoney
Money.class.php
-__construct+getValue +getCurrency
+toString+sameCurrency +equal
MoneyOps.class.php
:: +add
MoneyException.php
IncompatibleCurrenciesExceptionInvalidCurrencyException
InvalidMoneyValueException
MoneyOpsAddTest.php
+testSimpleAdd
MoneySameCurrTest.php
+testSame+testNotSame
MoneyEqTest.php
+testMemeValeurMemeDevise+testMemeValeurDeviseDifff//
88
Test unitaires – Exos 1
● QUnit
● Commencer à réfléchir à comment mettre en place les tests sur vos codes WebA/FmwkJS
money.js
money(v,curr)getValue
getCurrrencyequals
money_ops.js
money(v,curr)getValue
getCurrrencyequals
money_exc.js
DevisesIncompatibleExc
money_test.js
constructoraccesseurs
equals
money_test.html
money_ops_test.js
simpleAddmultiDevise
money_ops_test.html
money_test_suite.js
money_test.htmlmoney_ops_test.html
money_test_suite.html