Ecrire des tests automatisés est plus qu'un luxe pour toute équipe de développement logiciel agile. C'est un besoin et un outil essentiel pour trouver rapidement les bogues au cours des premières phases des cycles de développement logiciel. Lorsqu'une nouvelle fonctionnalité est encore en phase de développement, les développeurs peuvent exécuter des tests automatisés et voir comment d'autres parties du système sont affectées par ces modifications. Cet article explique comment accélérer les tests automatisés à l'aide du modèle d'objet de page dans Sélénium .
À travers automatisation des tests , il est possible de réduire le coût de la correction des bogues et d'apporter une amélioration globale au assurance qualité des logiciels (AQ) processus. Avec des tests appropriés, les développeurs ont une chance de trouver et de résoudre les bogues avant même d'arriver au contrôle qualité. L'automatisation des tests nous aide en outre à automatiser les cas de test et les fonctionnalités qui régressent constamment. De cette façon, les responsables qualité ont plus de temps pour tester d'autres parties de l'application. De plus, cela contribue à garantir la qualité du produit dans les versions de production. En conséquence, nous obtenons des produits effectivement plus stables et un processus d'AQ plus efficace.
Bien que l'écriture de tests automatisés puisse sembler une tâche facile pour les développeurs et les ingénieurs, il est toujours possible de se retrouver avec des tests mal implémentés et le coût élevé de la maintenance du code dans tout processus agile. Essayer de fournir constamment des changements ou des fonctionnalités dans tout projet de développement agile peut s'avérer coûteux lorsque des tests sont impliqués. La modification d'un élément sur une page Web sur laquelle reposent 20 tests nécessitera que l'un d'entre eux passe par ces 20 routines de test et les met à jour pour s'adapter à ce changement nouvellement introduit. Cela peut non seulement prendre beaucoup de temps, mais également un facteur de démotivation important lorsqu'il s'agit de mettre en œuvre des tests automatisés dès le début.
Mais que se passerait-il si nous pouvions effectuer le changement à un seul endroit et que chaque routine de test pertinente l'utilisait? Dans cet article, nous examinerons les tests automatisés dans Selenium et comment nous pouvons utiliser des modèles d'objet de page pour écrire des routines de test maintenables et réutilisables.
Modèle d'objet de page est un modèle de conception d'objet dans Selenium, où les pages Web sont représentées sous forme de classes et les différents éléments de la page sont définis comme des variables de la classe. Toutes les interactions utilisateur possibles peuvent alors être implémentées en tant que méthodes sur la classe:
clickLoginButton(); setCredentials(user_name,user_password);
Étant donné que les méthodes bien nommées dans les classes sont faciles à lire, cela fonctionne comme un moyen élégant d'implémenter des routines de test qui sont à la fois lisibles et plus faciles à maintenir ou à mettre à jour dans le futur. Par exemple:
Afin de prendre en charge le modèle d'objet de page, nous utilisons Usine de pages . Page Factory dans Selenium est une extension de Page Object et peut être utilisée de différentes manières. Dans ce cas, nous utiliserons Page Factory pour initialiser les éléments Web définis dans les classes de page Web ou les objets de page.
Les classes de page Web ou les objets de page contenant des éléments Web doivent être initialisés à l'aide de Page Factory avant de pouvoir utiliser les variables d'élément Web. Cela peut être fait simplement en utilisant initElements fonction sur PageFactory:
LoginPage page = new LoginPage(driver); PageFactory.initElements(driver, page);
Ou, encore plus simple:
LoginPage page = PageFactory.intElements(driver,LoginPage.class)
Ou, à l'intérieur du constructeur de classe de page Web:
public LoginPage(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); }
Page Factory initialisera chaque WebElement variable avec une référence à un élément correspondant sur la page Web réelle basée sur des «localisateurs» configurés. Cela se fait grâce à l'utilisation de @FindBy annotations. Avec cette annotation, nous pouvons définir une stratégie de recherche de l'élément, ainsi que les informations nécessaires à son identification:
@FindBy(how=How.NAME, using='username') private WebElement user_name;
Chaque fois qu'une méthode est appelée WebElement variable, le pilote la trouvera d'abord sur la page en cours, puis simulera l'interaction. Dans le cas où nous travaillons avec une page simple, nous savons que nous trouverons l'élément sur la page à chaque fois que nous le chercherons, et nous savons également que nous finirons par quitter cette page et ne pas y retourner, nous pouvons mettre en cache le champ recherché en utilisant une autre annotation simple:
@FindBy(how=How.NAME, using='username') @CacheLookup private WebElement user_name;
Cette définition entière de la variable WebElement peut être remplacée par sa forme beaucoup plus concise:
@FindBy(name='username') private WebElement user_name;
La @FindBy l'annotation prend en charge une poignée d'autres stratégies qui facilitent un peu les choses:
id, name, className, css, tagName, linkText, partialLinkText, xpath
@FindBy(id='username') private WebElement user_name; @FindBy(name='passsword') private WebElement user_password; @FindBy(className='h3') private WebElement label; @FindBy(css=”#content”) private WebElement text;
Une fois initialisées, ces variables WebElement peuvent ensuite être utilisées pour interagir avec les éléments correspondants sur la page. Le code suivant sera, par exemple:
user_password.sendKeys(password);
… Envoyer la séquence donnée de frappes au champ du mot de passe sur la page, et cela équivaut à:
driver.findElement(By.name(“user_password”)).sendKeys(password);
En continuant, vous rencontrerez souvent des situations où vous devez trouver une liste d'éléments sur une page, et c'est à ce moment-là @FindBys est très pratique:
@FindBys(@FindBy(css=”div[class=’yt-lockup-tile yt-lockup-video’]”))) private List videoElements;
Le code ci-dessus trouvera tous les div éléments ayant deux noms de classe «yt-lockup-tile» et «yt-lockup-video». Nous pouvons simplifier encore plus cela en le remplaçant par ce qui suit:
@FindBy(how=How.CSS,using='div[class=’yt-lockup-tile yt-lockup-video’]') private List videoElements;
De plus, vous pouvez utiliser @Trouver tout avec multiple @FindBy annotations pour rechercher des éléments qui correspondent à l'un des localisateurs donnés:
@FindAll({@FindBy(how=How.ID, using=”username”), @FindBy(className=”username-field”)}) private WebElement user_name;
Maintenant que nous pouvons représenter les pages Web sous forme de classes Java et utiliser Page Factory pour initialiser WebElement variables facilement, il est temps de voir comment nous pouvons écrire des tests Selenium simples en utilisant le modèle d'objet de page et Page Factory.
Pour notre didacticiel sur le modèle d'objet de page, automatisons l'inscription des développeurs à ApeeScape. Pour ce faire, nous devons automatiser les étapes suivantes:
Visitez www.toptal.com
Cliquez sur le bouton «Postuler en tant que développeur»
Sur la page du portail, vérifiez d'abord s'il est ouvert
Cliquez sur le bouton «Rejoindre ApeeScape»
Remplir le formulaire
Soumettez le formulaire en cliquant sur le bouton «Rejoindre ApeeScape»
Télécharger et installer Java JDK
Télécharger et installer Idée InteliJ
Créer un nouveau projet Maven
Liez «Project SDK» à votre JDK, par exemple: sous Windows «C: Program Files Java jdkxxx»
Configurer groupId et artifactId:
SeleniumTEST Test
junit junit ${junit.version} test org.seleniumhq.selenium selenium-firefox-driver ${selenium.version} org.seleniumhq.selenium selenium-support ${selenium.version} org.seleniumhq.selenium selenium-java ${selenium.version}
Remplacez la version Selenium et la version JUnit par les derniers numéros de version qui peuvent être trouvés en recherchant JUnit Maven sur Google et sur le site Selenium.
À ce stade, si la construction automatique est activée, les dépendances devraient commencer à se télécharger automatiquement. Sinon, activez simplement Plugins> installer> installer: installez sous le panneau Projets Maven sur le côté droit de votre IDE IntelliJ Idea.
Une fois le projet amorcé, nous pouvons commencer à créer notre package de test sous «src / test / java». Nommez le package «com.toptal» et créez deux autres packages sous celui-ci: «com.toptal.webpages» et «com.toptal.tests».
Nous conserverons nos classes Page Object / Page Factory sous «com.toptal.webpages» et les routines de test sous «com.toptal.tests».
Maintenant, nous pouvons commencer à créer nos classes d'objets de page.
Le tout premier que nous devons implémenter concerne la page d’accueil d’ApeeScape (www.toptal.com). Créez une classe sous «com.toptal.webpages» et nommez-la «HomePage».
package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.How; import org.openqa.selenium.support.PageFactory; public class HomePage { private WebDriver driver; //Page URL private static String PAGE_URL='https://www.toptal.com'; //Locators //Apply as Developer Button @FindBy(how = How.LINK_TEXT, using = 'APPLY AS A DEVELOPER') private WebElement developerApplyButton; //Constructor public HomePage(WebDriver driver){ this.driver=driver; driver.get(PAGE_URL); //Initialise Elements PageFactory.initElements(driver, this); } public void clickOnDeveloperApplyButton(){ developerApplyButton.click(); } }
Sur la page d’accueil d’ApeeScape, nous nous intéressons à un élément en particulier, à savoir le bouton «Postuler en tant que développeur». Nous pouvons trouver cet élément en faisant correspondre le texte, ce que nous faisons ci-dessus. Lors de la modélisation de pages Web en tant que classes d'objets de page, la recherche et l'identification des éléments peuvent souvent devenir une corvée. Avec Google Chrome ou les outils de débogage de Firefox, cela peut être facilité. En cliquant avec le bouton droit sur n'importe quel élément d'une page, vous pouvez activer l'option «Inspecter l'élément» dans le menu contextuel pour obtenir des informations détaillées sur l'élément.
Une méthode courante (et ma préférée) consiste à rechercher des éléments à l’aide de Firefox Extension FireBug , en combinaison avec le pilote Web Firefox dans Selenium. Après avoir installé et activé l'extension FireBug, vous pouvez faire un clic droit sur la page et sélectionner «Inspecter l'élément avec FireBug» pour ouvrir FireBug. Depuis l'onglet HTML de FireBug, vous pouvez copier le XPath, le chemin CSS, le nom de la balise ou «Id» (si disponible) de n'importe quel élément de la page.
En copiant le XPath de l'élément dans la capture d'écran ci-dessus, nous pouvons créer un champ WebElement pour celui-ci dans notre objet de page comme suit:
@FindBy(xpath = '/html/body/div[1]/div/div/header/div/h1') WebElement heading;
Ou pour simplifier les choses, nous pouvons utiliser ici le nom de balise «h1», à condition qu'il identifie de manière unique l'élément qui nous intéresse:
@FindBy(tagName = 'h1') WebElement heading;
Ensuite, nous avons besoin d'un objet de page qui représente la page du portail des développeurs, que nous pouvons atteindre en cliquant sur le bouton «Postuler en tant que développeur».
Sur cette page, nous avons deux éléments d'intérêt. Pour déterminer si la page s'est chargée, nous voulons vérifier l'existence de l'en-tête. Et nous voulons aussi un WebElement champ pour le bouton «Rejoindre ApeeScape».
package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class DeveloperPortalPage { private WebDriver driver; @FindBy(xpath = '/html/body/div[1]/div/div/header/div/h1') private WebElement heading; @FindBy(linkText = 'JOIN TOPTAL') private WebElement joinApeeScapeButton; //Constructor public DeveloperPortalPage (WebDriver driver){ this.driver=driver; //Initialise Elements PageFactory.initElements(driver, this); } //We will use this boolean for assertion. To check if page is opened public boolean isPageOpened(){ return heading.getText().toString().contains('Developer portal'); } public void clikOnJoin(){ joinApeeScapeButton.click(); } }
Et enfin, pour notre troisième et dernier objet page de ce projet, nous en définissons un qui représente la page contenant le formulaire de candidature développeur. Comme nous devons traiter ici un certain nombre de champs de formulaire, nous en définissons un WebElement variable pour chaque champ de formulaire. Nous trouvons chaque champ par son «id» et nous définissons des méthodes de setter spéciales pour chaque champ qui simulent des frappes pour les champs correspondants.
package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class DeveloperApplyPage { private WebDriver driver; @FindBy(tagName = 'h1') WebElement heading; @FindBy(id='developer_email') WebElement developer_email; @FindBy(id = 'developer_password') WebElement developer_password; @FindBy(id = 'developer_password_confirmation') WebElement developer_password_confirmation; @FindBy(id = 'developer_full_name') WebElement developer_full_name; @FindBy(id = 'developer_skype') WebElement developer_skype; @FindBy(id ='save_new_developer') WebElement join_toptal_button; //Constructor public DeveloperApplyPage(WebDriver driver){ this.driver=driver; //Initialise Elements PageFactory.initElements(driver, this); } public void setDeveloper_email(String email){ developer_email.clear(); developer_email.sendKeys(email); } public void setDeveloper_password(String password){ developer_password.clear(); developer_password.sendKeys(password); } public void setDeveloper_password_confirmation(String password_confirmation){ developer_password_confirmation.clear(); developer_password_confirmation.sendKeys(password_confirmation); } public void setDeveloper_full_name (String fullname){ developer_full_name.clear(); developer_full_name.sendKeys(fullname); } public void setDeveloper_skype (String skype){ developer_skype.clear(); developer_skype.sendKeys(skype); } public void clickOnJoin(){ join_toptal_button.click(); } public boolean isPageOpened(){ //Assertion return heading.getText().toString().contains('Apply to join our network as a developer'); } }
Avec les classes d'objets de page représentant nos pages et les interactions des utilisateurs comme méthodes, nous pouvons maintenant écrire notre routine de test simple sous la forme d'une série d'appels et d'assertions de méthode simples.
package com.toptal.tests; import com.toptal.webpages.DeveloperApplyPage; import com.toptal.webpages.DeveloperPortalPage; import com.toptal.webpages.HomePage; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import java.net.URL; import java.util.concurrent.TimeUnit; public class ApplyAsDeveloperTest { WebDriver driver; @Before public void setup(){ //use FF Driver driver = new FirefoxDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); } @Test public void applyAsDeveloper() { //Create object of HomePage Class HomePage home = new HomePage(driver); home.clickOnDeveloperApplyButton(); //Create object of DeveloperPortalPage DeveloperPortalPage devportal= new DeveloperPortalPage(driver); //Check if page is opened Assert.assertTrue(devportal.isPageOpened()); //Click on Join ApeeScape devportal.clikOnJoin(); //Create object of DeveloperApplyPage DeveloperApplyPage applyPage =new DeveloperApplyPage(driver); //Check if page is opened Assert.assertTrue(applyPage.isPageOpened()); //Fill up data applyPage.setDeveloper_email(' [email protected] '); applyPage.setDeveloper_full_name('Dejan Zivanovic Automated Test'); applyPage.setDeveloper_password('password123'); applyPage.setDeveloper_password_confirmation('password123'); applyPage.setDeveloper_skype('automated_test_skype'); //Click on join //applyPage.clickOnJoin(); } @After public void close(){ driver.close(); } }
À ce stade, la structure de votre projet doit ressembler à ceci:
quel outil un programmeur utiliserait-il pour visualiser la relation entre les modules ?
Si vous souhaitez lancer le test, sélectionnez «ApplyAsDeveloperTest» dans l'arborescence, faites un clic droit dessus puis sélectionnez Exécutez «ApplyAsDeveloperTest» .
Une fois le test exécuté, vous pouvez voir les résultats dans le coin inférieur gauche de votre IDE:
Page Object et Page Factory facilitent la modélisation des pages Web dans Selenium et les testent automatiquement et facilitent la vie des développeurs et AQ beaucoup plus simple. Lorsqu'elles sont bien faites, ces classes d'objets de page peuvent être réutilisées dans toute votre suite de tests et vous donner la possibilité de mettre en œuvre des tests Selenium automatisés pour vos projets dès le début, sans compromettre le développement agile. En faisant abstraction des interactions des utilisateurs dans vos modèles d'objet de page et en gardant vos routines de test légères et simples, vous pouvez adapter votre suite de tests à l'évolution des besoins avec peu d'effort.
J'espère avoir réussi à vous montrer comment écrire un code de test agréable et propre, facile à maintenir. Je terminerai l'article avec ma citation préférée du contrôle qualité:
En relation: Scraping Web avec un navigateur sans tête: un didacticiel de marionnettisteRéfléchissez à deux fois, codez une fois!
Le modèle d'objet de page est un modèle de conception d'objet dans Selenium. Les pages Web sont représentées comme des classes et les éléments de la page sont définis comme des variables sur la classe, de sorte que les interactions des utilisateurs peuvent ensuite être implémentées en tant que méthodes sur la classe.
Selenium est conçu pour automatiser les navigateurs Web, permettant ainsi aux ingénieurs logiciels d'accélérer et d'automatiser considérablement les tests. Bien que l'automatisation des tests soit sa principale utilisation, Selenium peut également être utilisé pour automatiser certaines actions répétitives, telles que les tâches d'administration de base.
Les tests de sélénium consistent à utiliser un ensemble d'outils logiciels Selenium pour faciliter l'automatisation des tests. Dans la plupart des cas, les ingénieurs en logiciel choisissent un à deux outils Selenium pour cette tâche, mais des outils supplémentaires peuvent être utilisés pour répondre à différents besoins.
Le modèle d'objet de page est un modèle de conception, comme indiqué précédemment dans cette section. Page Factory étend la fonctionnalité de modèle d'objet de page en introduisant des fonctionnalités plus avancées. Il permet aux utilisateurs d'initialiser des éléments spécifiques dans le modèle d'objet de page, à l'aide d'annotations.