I. Introduction▲
Lorsque vous développez un site Web, vous avez besoin de tester que les pages fonctionnent. Et ces tests doivent pouvoir s'automatiser lorsque le site grossit. Dans l'article Tutoriel sur le test d'applications Web avec Selenium, Denis Thomas nous présentait Selenium, l'outil Java le plus utilisé pour tester les IHM. Or Selenium n'est pas si simple à prendre en main.
Dans cet article, nous allons utiliser FluentLenium qui, comme son nom l'indique, permet de simplifier l'utilisation de Selenium tout en proposant de bonnes pratiques.
FluentLenium est une bibliothèque française : cocorico. Elle a été développée par Mathilde Lemée, qu'on croise régulièrement dans des grandes conférences comme Devoxx…
I-A. À propos▲
Découvrir une technologie n'est pas chose facile. En aborder plusieurs d'un coup l'est encore moins. Partant de ce constat, cet article a été écrit pour aller à l'essentiel. Les points importants sont présentés dans le corps de l'article et les éléments secondaires sont expliqués en annexe.
I-B. Avant de commencer▲
Pour écrire ce tutoriel, j'ai utilisé les éléments suivants :
- Java JDK 1.6.0_24-b07 ;
- Eclipse Indigo 3.7 JEE 64b ;
- Maven 3.0.3 ;
- Tomcat 7.0.35 ;
- Pretty Faces 3.3.2 ;
- JUnit 4.11 ;
- FluentLenium 0.9.1.
I-C. Mises à jour▲
xxx: création
II. Découverte du projet d'exemple▲
II-A. Télécharger, installer et importer le projet d'exemple▲
Pour commencer, je vous propose de télécharger le fichier Zip« fibo-webapp-fluentlenium.zip », contenant un projet Java-Maven d'exemple (une mini webapp) qui va nous servir de support visuel pour les fonctionnalités présentées dans la suite de cet article.
Cette webapp est celle que nous avions développée dans l'article « De jolies URL dans vos applications Web JSF avec Pretty Faces ».
Compilez le projet d'exemple et importez-le dans Eclipse (comme expliqué dans le tutoriel « Importer un projet Maven dans Eclipse en 5 minutes ») ou dans l'IDE de votre choix.
Installez ensuite la webapp dans le serveur d'application de votre choix, par exemple Tomcat 6, ce que vous pouvez faire directement depuis Eclipse.
Pour suivre ce tutoriel, vous pouvez vous contenter de lire les codes proposés ci-dessous (codes complets en annexe) et de faire confiance aux captures d'écran.
II-B. Ce que fait déjà le projet d'exemple▲
Le projet d'exemple est une petite webapp permettant de calculer plusieurs fonctions mathématiques célèbres. Cette application Web n'a rien de très complexe. Elle utilise le framework Web JSF, inclus dans Java JEE. Les fonctionnalités (calcul de la suite de Fibonacci et du factoriel) servent uniquement d'illustration.
La webapp est accessible à l'aide d'une adresse ressemblant à la suivante : http://localhost:8080/fibo-webapp-fluentlenium/
À partir du menu, on peut aller sur la page qui nous intéresse, permettant de calculer la suite de Fibonacci par exemple. C'est à cette fonction que nous allons plus particulièrement nous intéresser dans la suite. Par défaut, lorsqu'aucun rang n'a été précisé dans l'URL, la page affiche le résultat au rang « 2 », correspondant aux valeurs de base.
Il est bien entendu possible de calculer la suite de Fibonacci pour un autre rang, qu'on choisira à l'aide d'un champ de saisie.
Dans la suite, on va donc tester que ce parcours fonctionne bien.
III. Action▲
III-A. Maven▲
Durée estimée : 1 minute.
Pour utiliser FluentLenium, il faut ajouter une dépendance dans le fichier « pom.xml » . Ici on va utiliser la version FestAssert, car elle est pratique, mais on peut se contenter de JUnit.
<dependency>
<groupId>
org.fluentlenium</groupId>
<artifactId>
fluentlenium-festassert</artifactId>
<version>
0.9.1</version>
</dependency>
Il n'est pas obligatoire de coder les tests dans le même projet que la webapp. La plupart du temps, vous allez d'ailleurs tester des webapp dont vous n'aurez pas le code. Elles seront peut-être même écrites à l'aide d'une autre techno comme PHP, .net ou tout simplement en HTML classique.
Puis relancer une installation Maven.
mvn clean install eclipse:eclipse
En fonction des éléments déjà présents sur le disque dur, le résultat de l'installation Maven devrait ressembler à la trace suivante.
C:\dvp\fibo-webapp-fluentlenium>
set JAVA_HOME
=
C:\dev\javas\jdk1.6
.0_24
[INFO] Scanning for
projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building fibo-webapp-fluentlenium 1
.0
-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: http://repo1.maven.org/maven2/org/fluentlenium/fluentlenium-core/0
.9
.1
/fluentlenium-core-0
.9
.1
.pom
Downloaded: http://repo1.maven.org/maven2/org/fluentlenium/fluentlenium-core/0
.9
.1
/fluentlenium-core-0
.9
.1
.pom (
4
KB at 7
.8
KB/sec)
Downloading: http://repo1.maven.org/maven2/org/fluentlenium/fluentlenium-parent/0
.9
.1
/fluentlenium-parent-0
.9
.1
.pom
Downloaded: http://repo1.maven.org/maven2/org/fluentlenium/fluentlenium-parent/0
.9
.1
/fluentlenium-parent-0
.9
.1
.pom (
9
KB at 63
.2
KB/sec)
Downloading: http://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-java/2
.35
.0
/selenium-java-2
.35
.0
.pom
Downloaded: http://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-java/2
.35
.0
/selenium-java-2
.35
.0
.pom (
7
KB at 43
.4
KB/sec)
Downloading: http://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-parent/2
.35
.0
/selenium-parent-2
.35
.0
.pom
Downloaded: http://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-parent/2
.35
.0
/selenium-parent-2
.35
.0
.pom (
10
KB at 58
.8
KB/sec)
Downloading: http://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-android-driver/2
.35
.0
/selenium-android-driver-2
.35
.0
.pom
...
[INFO] Not writing settings - defaults suffice
[INFO] File C:\dvp\fibo-webapp-fluentlenium\.project already exists.
Additional settings will be preserved, run mvn eclipse:clean if
you want old settings to be removed.
[INFO] Wrote Eclipse project for
"fibo-webapp-fluentlenium"
to C:\dvp\fibo-webapp-fluentlenium.
[INFO]
Javadoc for
some artifacts is not available.
List of artifacts without a javadoc archive:
o org.apache.httpcomponents:httpclient:4
.2
.1
o org.apache.httpcomponents:httpcore:4
.2
.1
o org.apache.httpcomponents:httpmime:4
.2
.3
o io.netty:netty:3
.5
.2
.Final
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1
:55
.578s
[INFO] Finished at: Sat Nov 30
16
:33
:54
CET 2013
[INFO] Final Memory: 13M/118M
[INFO] ------------------------------------------------------------------------
On doit ensuite faire un refresh (touche F5) dans Eclipse pour faire apparaitre FluentLenium dans la liste des bibliothèques référencées.
III-B. Page Object Pattern▲
Durée estimée : 1 minute.
On va donc s'intéresser à trois écrans : la page d'accueil, la page pour calculer la suite de Fibonacci et la page des résultats. Avant de savoir si ces pages fonctionnent, encore faut-il savoir naviguer dessus.
FluentLenium recommande d'employer le pattern « Page Object Pattern » au lieu de coder les appels en dur.
On va donc créer trois classes dédiées à cette opération : HomePage, FiboPage et FiboResultPage. Il faut redéfinir les méthodes « getUrl() » et « isAt() ». Elles servent respectivement à indiquer l'adresse cible et savoir si on est bien arrivé. Voici ce que ça donne pour la première :
public
class
HomePage extends
FluentPage {
private
final
static
String URL =
"http://localhost:8080/fibo-webapp-fluentlenium"
;
private
final
static
String TITLE =
"fibowebapp"
;
@Override
public
String getUrl
(
) {
return
URL;
}
@Override
public
void
isAt
(
) {
Assertions.assertThat
(
title
(
)).isEqualTo
(
TITLE);
}
}
Le titre des pages reste le même sur tout le site. Du coup, le test de la valeur du titre permet de savoir qu'on est sur le bon site, mais pas forcément sur la page d'accueil. Ici, ce n'est pas bien grave puisqu'on est surtout intéressé de savoir qu'on est bien sur le site, lorsqu'on parle de l'accueil, avec les menus et les éléments englobants. Si on veut vraiment la page d'accueil (et aucune autre), on devra être plus spécifique et on utilisera une des techniques qu'on va voir dans la suite.
Nous reviendrons rapidement sur les deux autres pages.
III-C. Un premier test▲
Durée estimée : 1 minute.
On peut maintenant tester si les pages fonctionnent bien. Voyons déjà ce que ça donne avec l'accueil. Pour cela, on va écrire un petit test :
public
class
HomeTest extends
FluentTest {
public
WebDriver webDriver =
new
HtmlUnitDriver
(
);
@Page
public
HomePage homePage;
@Test
public
void
testHomePage
(
) {
// Aller sur la page d'accueil
goTo
(
homePage);
// Verifier qu'on est bien arrive
homePage.isAt
(
);
}
@Override
public
WebDriver getDefaultDriver
(
) {
return
webDriver;
}
}
Avant de lancer le test, il faut évidemment démarrer le serveur.
III-D. Test de navigation▲
Durée estimée : 2 minutes.
Un test de navigation teste qu'on peut naviguer dans le site. Ici, on va simplement cliquer sur le menu « Fibonacci » et vérifier qu'on arrive sur la bonne page. Pour cela, on va partir de la page d'accueil.
public
class
FiboTest extends
FluentTest {
public
WebDriver webDriver =
new
HtmlUnitDriver
(
);
@Page
public
HomePage homePage;
@Page
public
FiboPage fiboPage;
@Test
public
void
testFiboPage
(
) {
// Aller sur la page d'accueil
goTo
(
homePage);
homePage.isAt
(
);
// Cliquer sur le menu
clicFiboMenu
(
);
// Verifier qu'on est sur la page Fibonacci
fiboPage.isAt
(
);
}
private
void
clicFiboMenu
(
) {
// TODO
}
@Override
public
WebDriver getDefaultDriver
(
) {
return
webDriver;
}
}
Il reste à savoir ce qu'on va mettre dans la méthode « clicFiboMenu() ». Le dire en français est simple : on veut cliquer sur le lien « Fibonacci ». Le faire est un peu plus complexe, d'autant qu'il y a plusieurs manières d'y parvenir.
On peut rechercher le texte dans la page et cliquer dessus. Personnellement je ne suis pas fan de cette pratique, car elle nécessite beaucoup de travail dans un environnement multilingue. On peut aussi chercher le lien en parcourant la structure des balises de la page. Mais la moindre évolution dans la page rendra tous les tests obsolètes. On peut encore trouver le lien grâce à son id ou à un attribut de style. C'est ce que nous allons faire.
On va donc ajouter des identifiants à nos liens de menu, comme ça devrait être le cas dans tous les sites Web dignes de ce nom :
<pretty:
link mappingId
=
"fibonacci"
id
=
"fibo"
>
Fibonacci
</pretty
:
link>
Au niveau du HTML généré, cela va se traduire par :
<a id
=
"fibo"
href
=
"/fibo-webapp-fluentlenium/fibo"
>
Fibonacci</a>
On peut désormais utiliser cet id dans le test :
private
void
clicFiboMenu
(
) {
$(
"#fibo"
).click
(
);
}
En voyant « $("#fibo") » dans ce bout de code, vous vous dites sûrement que ça ressemble à du jQuery et vous auriez bien raison. Mais n'allez pas vous imaginer que c'en est. Ça y ressemble (volontairement), mais c'est bien du Java. En effet, n'oubliez pas que le dollar est autorisé dans un nom de méthode, même si c'est très rarement utilisé. Vous trouverez la méthode « $(..) » dans la classe « Fluent ». Pour le coup, ici, c'est bien pratique, surtout si on fait le rapprochement avec jQuery qu'on utilise, côté navigateur (i.e. côté client), pour rechercher des éléments dans le DOM.
Il reste encore à écrire la méthode « isAt() » de « FiboPage ». Contrairement à la page d'accueil, on ne va pas se contenter de la valeur du titre.
Dans le code, on a ça :
<
div id=
"content"
>
<
h1>
Fibonacci</
h1>
<
form id=
"j_idt22"
enctype=
"application/x-www-form-urlencoded"
action=
"/fibo-webapp-fluentlenium/fibo?r=2"
method=
"post"
name=
"j_idt22"
>
</
div>
Du coup, on peut prendre l'élément « h1 », représentant le titre de la section (supposé unique) dans la « div » avec l'id « content » :
public
class
FiboPage extends
FluentPage {
@Override
public
void
isAt
(
) {
Assertions.assertThat
(
find
(
"#content h1"
).first
(
).getText
(
) )
.isEqualTo
(
"Fibonacci"
);
}
}
Pour comprendre ce bout de code, il faut savoir que la méthode « find() » renvoie une liste.
III-E. Test du formulaire▲
Durée estimée : 2 minutes.
Pour tester le formulaire, c'est à peine plus difficile. On va d'abord naviguer vers la bonne page, puis choisir un rang, puis vérifier qu'on arrive sur la page des résultats et enfin tester les valeurs fournies.
On peut se dire qu'on est sur la bonne page, si on voit le tableau des résultats. Pour l'identifier facilement, on peut de nouveau ajouter un id dans le code HTML :
<
p id=
"resultats"
>
<
table border=
"1"
>
<
thead>
<
tr>
<
th>
Rang</
th>
<
th>
Valeur</
th>
La suite est relativement la même que pour les pages précédentes :
public
class
FiboResultPage extends
FluentPage {
@Override
public
void
isAt
(
) {
Assertions.assertThat
(
find
(
"#resultats table"
).size
(
)).isGreaterThan
(
0
);
}
}
Dans la suite, on va rester dans la même classe de test : pas la peine de multiplier inutilement les tests alors qu'on reste dans le même sujet… Par contre, on en profite pour factoriser un peu.
public
class
FiboTest extends
FluentTest {
public
WebDriver webDriver =
new
HtmlUnitDriver
(
);
@Page
public
HomePage homePage;
@Page
public
FiboPage fiboPage;
@Page
FiboResultPage fiboResultPage;
@Test
public
void
testFiboPage
(
) {
goToFibo
(
);
}
@Test
public
void
testFiboCalcul
(
) {
// Arrange
final
String value =
"8"
;
final
String expected =
"21"
;
// Act
goToFibo
(
);
selectValue
(
value);
clicCalculerBouton
(
);
fiboResultPage.isAt
(
);
// Assert
Assertions.assertThat
(
findFirst
(
"#res_"
+
value).getText
(
)).isEqualTo
(
expected);
}
private
void
goToFibo
(
) {
goTo
(
homePage);
homePage.isAt
(
);
clicFiboMenu
(
);
fiboPage.isAt
(
);
}
private
void
selectValue
(
final
String value) {
}
private
void
clicCalculerBouton
(
) {
}
...
}
Il ne reste plus qu'à coder la sélection d'une valeur et le clic sur le bouton. Pour ce dernier, c'est aussi simple que pour le clic sur le menu.
private
void
clicCalculerBouton
(
) {
fiboPage.submit
(
);
}
Comme l'action de validation du formulaire est propre à la page, on va plutôt la coder dans « FiboPage » :
public
void
submit
(
) {
submit
(
"#fiboform"
);
}
Pour pouvoir faire ça de cette manière, il suffit de donner l'id « fiboform » au formulaire. Le code HTML n'en sera que plus propre. La bibliothèque va aller chercher toute seule les boutons du formulaire.
Pour choisir une valeur, ce n'est pas beaucoup plus difficile.
private
void
selectValue
(
final
String value) {
fillSelect
(
"select"
, FilterConstructor.withId
(
).endsWith
(
"fiboselect"
)).withValue
(
value);
}
Vous vous demandez certainement pourquoi on n'indique pas simplement « #fiboselect » comme id. Cela vient du fait que JSF en a changé la valeur en la préfixant par quelque chose qu'on ne peut pas déterminer à l'avance…
On peut maintenant lancer le test qui devrait passer au vert, pour indiquer que tout est bon.
Comme me l'a fait très justement remarquer Nemek, un collègue de Developpez.com, s'il y a un préfixe, c'est qu'il y a un formulaire. Le préfixe est l'id du formulaire. Il suffit donc de donner un id au formulaire :
<
h:form id=
"fiboform"
>
...
Du coup, on peut trouver la balise « SELECT » à l'aide de l'id généré « fiboform:fiboselect » et donc simplifier le test en conséquence :
private
void
selectValue
(
final
String value) {
//fillSelect("select", FilterConstructor.withId().endsWith("fiboselect")).withValue(value);
fillSelect
(
"#fiboform
\\
:fiboselect"
).withValue
(
value);
}
III-F. Des tests et des services▲
Durée estimée : 2 minutes.
On a déjà bien utilisé le POP (Page Object Pattern), mais nous ne sommes pas allé au bout du concept. En effet, on peut séparer la partie test, qui reprend du fonctionnel, de la partie page, qui gère ce qui est technique comme les sélecteurs CSS (les id pour nous).
Pour faire simple, tout ce qui contient un id (hors test de résultat, quoique ?… cf. code complet en annexe) doit se trouver dans un objet Page. Et les tests utiliseront alors les nouveaux services proposés par les pages.
Pour la page d'accueil, tout est déjà bon. Pour son menu, on peut déporter le clic sur un menu particulier dans l'objet Page.
public
class
HomePage extends
FluentPage {
...
public
void
clickOnFibonacciMenu
(
) {
$(
"#fibo"
).click
(
);
}
public
class
FiboTest extends
FluentTest {
...
private
void
goToFibo
(
) {
goTo
(
homePage);
homePage.isAt
(
);
//clicFiboMenu();
homePage.clickOnFibonacciMenu
(
);
fiboPage.isAt
(
);
}
On pourrait même avoir un POP spécifique pour le menu, qu'on inclurait dans les autres pages, comme une sous-page.
On fait de même pour la sélection d'un rang dans la liste et le clic sur le bouton de calcul :
public
class
FiboPage extends
FluentPage {
...
public
void
selectValue
(
final
String value) {
fillSelect
(
"#fiboform
\\
:fiboselect"
).withValue
(
value);
}
public
class
FiboTest extends
FluentTest {
...
@Test
public
void
testFiboCalcul
(
) {
// Arrange
final
String value =
"8"
;
final
String expected =
"21"
;
// Act
goToFibo
(
);
//selectValue(value);
fiboPage.selectValue
(
value);
//clicCalculerBouton();
fiboPage.submit
(
);
fiboResultPage.isAt
(
);
// Assert
Assertions.assertThat
(
findFirst
(
"#res_"
+
value).getText
(
)).isEqualTo
(
expected);
}
Le code complet est proposé en annexe…
IV. Conclusion▲
Le contrat n'est pas tout à fait rempli puisqu'il aura fallu un peu plus de cinq minutes pour venir à bout de ce petit tutoriel. Toutefois on n'en est pas loin.
Les exemples utilisés peuvent sembler simples, voire trop simples, mais ils devraient être représentatifs des pages auxquelles vous allez (probablement) vous attaquer en premier. En quelques cas, on couvre donc une bonne partie des problématiques. Toutefois, on pourra aller bien plus loin avec FluentLenium (ainsi qu'avec Selenium), comme écrire des tests d'acceptance en mode BDD (Behavior Driven Developpement) par exemple. Ce sera le sujet d'un prochain article, car FluentLenium existe aussi en version utilisant Cucumber.
Notez tout de même qu'on a pris le problème un peu à l'envers puisqu'on écrit les tests après coup. On a donc été obligé d'adapter des pages déjà existantes. Dans une démarche TDD (Test Driven Development), BDD (Behavior Driven Development) ou encore 3T (Tests en Trois Temps), on aurait dû écrire les tests avant le code des pages. On aurait donc décidé à l'avance des points importants à repérer dans les pages. Et on les aurait écrites comme il faut, durant le développement, et non juste modifiées pour les faire coller à un besoin a posteriori…
Vos retours nous aident à améliorer nos publications. N'hésitez donc pas à commenter cet article sur le forum : 1 commentaire
V. Remerciements▲
D'abord j'adresse mes remerciements aux créateurs de FluentLenium, qui simplifient mon quotidien, pour avoir développé une bibliothèque aussi utile et pour la maintenir. Je n'oublie pas tous les contributeurs qui rendent le projet encore meilleur.
Plus spécifiquement en ce qui concerne cet article, je tiens à remercier Mathilde Lemée et les membres de Developpez.com qui m'ont aidé à écrire cet article : Nemek, Mickael Baron et Claude Leloup.
VI. Annexes▲
VI-A. Liens▲
FluentLenium :https://github.com/FluentLenium/FluentLenium/wiki
Blog de Mathilde :http://www.java-freelance.fr/
Selenium :http://www.seleniumhq.org/
Cucumber :http://cukes.info/
VI-B. Liens perso▲
Retrouvez ma page et mes autres articles sur Developpez.com à l'adresse
https://thierry-leriche-dessirier.developpez.com/#page_articlesTutoriels
Suivez-moi sur Twitter : @thierryleriche (https://twitter.com/thierryleriche)@thierryleriche
Et mon site perso : www.icauda.comICAUDA
VI-C. Code complet▲
<
?xml version=
"1.0"
encoding=
"UTF-8"
?>
<
ui:composition xmlns=
"http://www.w3.org/1999/xhtml"
xmlns
:
ui=
"http://java.sun.com/jsf/facelets"
xmlns
:
h=
"http://java.sun.com/jsf/html"
xmlns
:
f=
"http://java.sun.com/jsf/core"
xmlns
:
c=
"http://java.sun.com/jsp/jstl/core"
xmlns
:
pretty=
"http://ocpsoft.com/prettyfaces"
>
<
div id=
"menus"
>
<
pretty:link mappingId=
"fibonacci"
id=
"fibo"
>
Fibonacci
</
pretty:link><
br/>
<
pretty:link mappingId=
"fibonacci2"
id=
"fibo10"
>
<
f:param value=
"10"
/>
Fibonacci de 10
</
pretty:link><
br/>
<
pretty:link mappingId=
"fibonacci2"
id=
"fiboDef"
>
<
f:param value=
"#{fiboBean.defaultRang}"
/>
Fibonacci au rang DEFAULT_RANG
</
pretty:link><
br/>
<
pretty:link mappingId=
"factoriel"
id=
"fact"
>
Factoriel
</
pretty:link><
br/>
</
div>
</
ui:composition>
<
ui:composition xmlns=
"http://www.w3.org/1999/xhtml"
xmlns
:
ui=
"http://java.sun.com/jsf/facelets"
xmlns
:
f=
"http://java.sun.com/jsf/core"
xmlns
:
h=
"http://java.sun.com/jsf/html"
xmlns
:
c=
"http://java.sun.com/jsp/jstl/core"
template=
"/template.xhtml"
>
<
ui:define name=
"mainContent"
>
<
div id=
"content"
>
<
h1>
Fibonacci</
h1>
<
h:form id=
"fiboform"
>
<
table>
<
tr>
<
td>
Rang :</
td>
<
td>
<
h:selectOneMenu id=
"fiboselect"
value=
"#{fiboBean.rang}"
>
<
c:forEach var
=
"entry"
begin=
"1"
end=
"90"
>
<
f:selectItem itemLabel=
"#{entry}"
itemValue=
"#{entry}"
/>
</
c:forEach>
</
h:selectOneMenu >
</
td>
<
td>
<
h:commandButton id=
"fibobutton"
value=
"Calculer"
action=
"#{fiboBean.calculer}"
/>
</
td>
</
tr>
</
table>
<
c:if
test=
"#{fiboBean.valeur ne null}"
>
<
p>
La valeur de la suite de Fibonacci pour le rang <
b>
#{
fiboBean.rang}</
b>
est <
b>
#{
fiboBean.valeur}</
b>
.</
p>
</
c:if
>
<
c:if
test=
"#{fiboBean.valeurs ne null}"
>
<
p id=
"resultats"
>
<
table border=
"1"
>
<
thead>
<
tr>
<
th>
Rang</
th>
<
th>
Valeur</
th>
<
th>
Valeur approximative</
th>
<
th>
Approximation</
th>
</
tr>
</
thead>
<
tbody>
<
c:forEach var
=
"item"
items=
"#{fiboBean.valeursInversees}"
>
<
tr>
<
td>
#{
item.rang}</
td>
<
td id=
"res_#{item.rang}"
>
#{
item.valeurExacte}</
td>
<
td>
#{
item.valeurApproximative}</
td>
<
td>
#{
item.approximation}</
td>
</
tr>
</
c:forEach>
</
tbody>
</
table>
</
p>
</
c:if
>
</
h:form>
</
div>
</
ui:define>
</
ui:composition>
package
com.dvp.fibowebapp.page;
import
org.fest.assertions.Assertions;
import
org.fluentlenium.core.FluentPage;
public
class
HomePage extends
FluentPage {
private
final
static
String URL =
"http://localhost:8080/fibo-webapp-fluentlenium"
;
private
final
static
String TITLE =
"fibowebapp"
;
@Override
public
String getUrl
(
) {
return
URL;
}
@Override
public
void
isAt
(
) {
Assertions.assertThat
(
title
(
)).isEqualTo
(
TITLE);
}
public
void
clickOnFibonacciMenu
(
) {
$(
"#fibo"
).click
(
);
}
}
package
com.dvp.fibowebapp.page;
import
org.fest.assertions.Assertions;
import
org.fluentlenium.core.FluentPage;
public
class
FiboPage extends
FluentPage {
@Override
public
void
isAt
(
) {
Assertions.assertThat
(
find
(
"#content h1"
).first
(
).getText
(
)).isEqualTo
(
"Fibonacci"
);
}
public
void
submit
(
) {
submit
(
"#fiboform"
);
}
public
void
selectValue
(
final
String value) {
fillSelect
(
"#fiboform
\\
:fiboselect"
).withValue
(
value);
}
}
package
com.dvp.fibowebapp.page;
import
org.fest.assertions.Assertions;
import
org.fluentlenium.core.FluentPage;
public
class
FiboResultPage extends
FluentPage {
@Override
public
void
isAt
(
) {
Assertions.assertThat
(
find
(
"#resultats table"
).size
(
)).isGreaterThan
(
0
);
}
public
String getResultat
(
final
String indice) {
return
findFirst
(
"#res_"
+
indice).getText
(
);
}
}
package
com.dvp.fibowebapp;
import
org.fluentlenium.adapter.FluentTest;
import
org.fluentlenium.core.annotation.Page;
import
org.junit.Test;
import
org.openqa.selenium.WebDriver;
import
org.openqa.selenium.htmlunit.HtmlUnitDriver;
import
com.dvp.fibowebapp.page.HomePage;
public
class
HomeTest extends
FluentTest {
public
WebDriver webDriver =
new
HtmlUnitDriver
(
);
@Page
public
HomePage homePage;
@Test
public
void
testHomePage
(
) {
goTo
(
homePage);
homePage.isAt
(
);
}
@Override
public
WebDriver getDefaultDriver
(
) {
return
webDriver;
}
}
package
com.dvp.fibowebapp;
import
org.fest.assertions.Assertions;
import
org.fluentlenium.adapter.FluentTest;
import
org.fluentlenium.core.annotation.Page;
import
org.junit.Test;
import
org.openqa.selenium.WebDriver;
import
org.openqa.selenium.htmlunit.HtmlUnitDriver;
import
com.dvp.fibowebapp.page.FiboPage;
import
com.dvp.fibowebapp.page.FiboResultPage;
import
com.dvp.fibowebapp.page.HomePage;
public
class
FiboTest extends
FluentTest {
public
WebDriver webDriver =
new
HtmlUnitDriver
(
);
@Page
public
HomePage homePage;
@Page
public
FiboPage fiboPage;
@Page
FiboResultPage fiboResultPage;
@Test
public
void
testFiboPage
(
) {
goToFibo
(
);
}
@Test
public
void
testFiboCalcul
(
) {
// Arrange
final
String rang =
"8"
;
final
String expected =
"21"
;
// Act
goToFibo
(
);
// selectValue(value);
fiboPage.selectValue
(
rang);
// clicCalculerBouton();
fiboPage.submit
(
);
fiboResultPage.isAt
(
);
// Assert
Assertions.assertThat
(
fiboResultPage.getResultat
(
rang)).isEqualTo
(
expected);
}
private
void
goToFibo
(
) {
goTo
(
homePage);
homePage.isAt
(
);
// clicFiboMenu();
homePage.clickOnFibonacciMenu
(
);
fiboPage.isAt
(
);
}
// private void selectValue(final String value) {
// fillSelect("select",
// FilterConstructor.withId().endsWith("fiboselect")).withValue(value);
// fillSelect("#fiboform\\:fiboselect").withValue(value);
// }
// private void clicCalculerBouton() {
// fiboPage.submit();
// }
// private void clicFiboMenu() {
// $("#fibo").click();
// }
@Override
public
WebDriver getDefaultDriver
(
) {
return
webDriver;
}
}