page object model with page factory selenium tutorial
Ce tutoriel détaillé explique tout sur le modèle d'objet de page (POM) avec Pagefactory à l'aide d'exemples. Vous pouvez également apprendre la mise en œuvre de POM dans Selenium:
Dans ce didacticiel, nous allons comprendre comment créer un modèle d'objet de page à l'aide de l'approche Page Factory. Nous nous concentrerons sur:
- Classe d'usine
- Comment créer un POM de base à l'aide d'un modèle de fabrique de pages
- Différentes annotations utilisées dans l'approche Page Factory
Avant de voir ce qu'est Pagefactory et comment il peut être utilisé avec le modèle d'objet de page, comprenons ce qu'est le modèle d'objet de page, communément appelé POM.
=> Visitez ici pour voir la série de formation Selenium pour tous.
Ce que vous apprendrez:
- Qu'est-ce que le modèle d'objet de page (POM)?
- Qu'est-ce que Pagefactory?
- POM utilisant Page Factory
- Tutoriels vidéo - POM avec Page Factory
- Étapes pour créer un POM à l'aide d'un modèle de fabrique de pages
- Couche de page
- Étapes pour créer un POM avec un exemple en temps réel
- Couche de test
- Hiérarchie des types d'annotations utilisée pour déclarer des éléments Web
- Plus sur PageFactory.initElements ()
- Questions fréquemment posées
- Conclusion
Qu'est-ce que le modèle d'objet de page (POM)?
Les terminologies théoriques décrivent les Modèle d'objet de page en tant que modèle de conception utilisé pour créer un référentiel d'objets pour les éléments Web disponibles dans l'application testée. Peu d'autres y font référence comme un cadre d'automatisation Selenium pour l'application en cours de test.
Cependant, ce que j'ai compris à propos du terme modèle d'objet de page est:
#1) Il s'agit d'un modèle de conception dans lequel vous disposez d'un fichier de classe Java distinct correspondant à chaque écran ou page de l'application. Le fichier de classe peut inclure le référentiel d'objets des éléments de l'interface utilisateur ainsi que des méthodes.
#deux) Dans le cas où une page contient d'énormes éléments Web, la classe du référentiel d'objets pour une page peut être séparée de la classe qui inclut des méthodes pour la page correspondante.
Exemple: Si la page Enregistrer un compte comporte de nombreux champs d'entrée, il peut y avoir une classe RegisterAccountObjects.java qui forme le référentiel d'objets pour les éléments de l'interface utilisateur sur la page d'enregistrement des comptes.
Un fichier de classe distinct RegisterAccount.java étendant ou héritant de RegisterAccountObjects qui inclut toutes les méthodes exécutant différentes actions sur la page peut être créé.
# 3) En outre, il pourrait y avoir un package générique avec un fichier {roperties, des données de test Excel et des méthodes communes sous un package.
Exemple: DriverFactory qui peut être utilisé très facilement dans toutes les pages de l'application
Comprendre POM avec l'exemple
Vérifier ici pour en savoir plus sur POM.
Voici un aperçu de la page Web:
Cliquer sur chacun de ces liens redirigera l'utilisateur vers une nouvelle page.
Voici un aperçu de la façon dont la structure du projet avec Selenium est construite à l'aide du modèle d'objet Page correspondant à chaque page du site Web. Chaque classe Java comprend un référentiel d'objets et des méthodes pour effectuer différentes actions dans la page.
En outre, il y aura un autre JUNIT ou TestNG ou un fichier de classe Java invoquant des appels aux fichiers de classe de ces pages.
Pourquoi utilisons-nous le modèle d'objet de page?
Il y a un buzz autour de l'utilisation de ce puissant framework Selenium appelé POM ou modèle d'objet de page. Maintenant, la question se pose comme «Pourquoi utiliser POM?».
La réponse simple à cela est que POM est une combinaison de cadres basés sur les données, modulaires et hybrides. Il s’agit d’une approche qui consiste à organiser systématiquement les scripts de manière à faciliter la gestion du code par le contrôle qualité et à éviter tout code redondant ou dupliqué.
Par exemple, s'il y a un changement dans la valeur du localisateur sur une page spécifique, alors il est très facile d'identifier et de faire ce changement rapide uniquement dans le script de la page respective sans impacter le code ailleurs.
Nous utilisons le concept de modèle d'objet de page dans Selenium Webdriver pour les raisons suivantes:
- Un référentiel d'objets est créé dans ce modèle POM. Il est indépendant des cas de test et peut être réutilisé pour un projet différent.
- La convention de dénomination des méthodes est très simple, compréhensible et plus réaliste.
- Sous le modèle d'objet Page, nous créons des classes de page qui peuvent être réutilisées dans un autre projet.
- Le modèle objet Page est facile pour le framework développé en raison de ses nombreux avantages.
- Dans ce modèle, des classes séparées sont créées pour différentes pages d'une application Web comme la page de connexion, la page d'accueil, la page de détails des employés, la page de changement de mot de passe, etc.
- S'il y a un changement dans un élément d'un site Web, nous n'avons besoin de faire des changements que dans une classe, et pas dans toutes les classes.
- Le script conçu est plus réutilisable, lisible et maintenable dans l'approche du modèle d'objet de page.
- Sa structure de projet est assez simple et compréhensible.
- Peut utiliser PageFactory dans le modèle d'objet de page afin d'initialiser l'élément Web et de stocker des éléments dans le cache.
- TestNG peut également être intégré dans l'approche de modèle d'objet de page.
Implémentation de POM simple dans le sélénium
# 1) Scénario pour automatiser
Nous automatisons maintenant le scénario donné à l'aide du modèle d'objet de page.
Le scénario est expliqué ci-dessous:
Étape 1: Lancez le site «https: //demo.vtiger.com».
Étape 2: Entrez les informations d'identification valides.
Étape 3: Connectez-vous au site.
Étape 4: Vérifiez la page d'accueil.
Étape 5: Déconnectez-vous du site.
Étape 6: Fermez le navigateur.
# 2) Scripts Selenium pour le scénario ci-dessus dans POM
Nous créons maintenant la structure POM dans Eclipse, comme expliqué ci-dessous:
Étape 1: Créer un projet dans Eclipse - Structure basée sur POM:
a) Créer un projet «Modèle d'objet de page».
b) Créez 3 Package sous le projet.
- bibliothèque
- pages
- cas de test
Bibliothèque: En dessous, nous mettons ces codes qui doivent être appelés encore et encore dans nos cas de test comme le lancement du navigateur, les captures d'écran, etc. L'utilisateur peut ajouter plus de classes en dessous en fonction des besoins du projet.
Pages: En vertu de cela, des classes sont créées pour chaque page de l'application Web et peuvent ajouter plus de classes de page en fonction du nombre de pages de l'application.
Cas de test: En dessous, nous écrivons le cas de test de connexion et pouvons ajouter d'autres cas de test si nécessaire pour tester l'ensemble de l'application.
c) Les classes sous les packages sont affichées dans l'image ci-dessous.
Étape deux: Créez les classes suivantes sous le package de bibliothèque.
Browser.java: Dans cette classe, 3 navigateurs (Firefox, Chrome et Internet Explorer) sont définis et il est appelé dans le cas de test de connexion. En fonction de l'exigence, l'utilisateur peut également tester l'application dans différents navigateurs.
package library; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.ie.InternetExplorerDriver; public class Browser { static WebDriver driver; public static WebDriver StartBrowser(String browsername , String url) { // If the browser is Firefox if (browsername.equalsIgnoreCase('Firefox')) { // Set the path for geckodriver.exe System.setProperty('webdriver.firefox.marionette',' E://Selenium//Selenium_Jars//geckodriver.exe '); driver = new FirefoxDriver(); } // If the browser is Chrome else if (browsername.equalsIgnoreCase('Chrome')) { // Set the path for chromedriver.exe System.setProperty('webdriver.chrome.driver','E://Selenium//Selenium_Jars//chromedriver.exe'); driver = new ChromeDriver(); } // If the browser is IE else if (browsername.equalsIgnoreCase('IE')) { // Set the path for IEdriver.exe System.setProperty('webdriver.ie.driver','E://Selenium//Selenium_Jars//IEDriverServer.exe'); driver = new InternetExplorerDriver(); } driver.manage().window().maximize(); driver.get(url); return driver; } }
ScreenShot.java: Dans cette classe, un programme de capture d'écran est écrit et il est appelé dans le cas de test lorsque l'utilisateur souhaite prendre une capture d'écran indiquant si le test échoue ou réussit.
package library; import java.io.File; import org.apache.commons.io.FileUtils; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; public class ScreenShot { public static void captureScreenShot(WebDriver driver, String ScreenShotName) { try { File screenshot=((TakesScreenshot)driver).getScreenshotAs(OutputType. FILE ); FileUtils.copyFile(screenshot, new File('E://Selenium//'+ScreenShotName+'.jpg')); } catch (Exception e) { System. out .println(e.getMessage()); e.printStackTrace(); } } }
Étape 3 : Créez des classes de page sous le package de pages.
HomePage.java: Il s'agit de la classe de page d'accueil, dans laquelle tous les éléments de la page d'accueil et les méthodes sont définis.
package pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class HomePage { WebDriver driver; By logout = By.id('p_lt_ctl03_wSOB_btnSignOutLink'); By home = By.id('p_lt_ctl02_wCU2_lblLabel'); //Constructor to initialize object public HomePage(WebDriver dr) { this .driver=dr; } public String pageverify() { return driver.findElement(home).getText(); } public void logout() { driver.findElement(logout).click(); } }
LoginPage.java: Il s'agit de la classe de page de connexion, dans laquelle tous les éléments de la page de connexion et des méthodes sont définis.
package pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class LoginPage { WebDriver driver; By UserID = By.xpath('//*(contains(@id,'Login1_UserName'))'); By password = By.xpath('//*(contains(@id,'Login1_Password'))'); By Submit = By.xpath('//*(contains(@id,'Login1_LoginButton'))'); //Constructor to initialize object public LoginPage(WebDriver driver) { this .driver = driver; } public void loginToSite(String Username, String Password) { this .enterUsername(Username); this .enterPasssword(Password); this .clickSubmit(); } public void enterUsername(String Username) { driver.findElement(UserID).sendKeys(Username); } public void enterPasssword(String Password) { driver.findElement(password).sendKeys(Password); } public void clickSubmit() { driver.findElement(Submit).click(); } }
Étape 4: Créez des scénarios de test pour le scénario de connexion.
LoginTestCase.java: Il s'agit de la classe LoginTestCase, où le scénario de test est exécuté. L'utilisateur peut également créer plus de cas de test selon les besoins du projet.
package testcases; import java.util.concurrent.TimeUnit; import library.Browser; import library.ScreenShot; import org.openqa.selenium.WebDriver; import org.testng.Assert; import org.testng.ITestResult; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import pages.HomePage; import pages.LoginPage; public class LoginTestCase { WebDriver driver; LoginPage lp; HomePage hp; int i = 0; // Launch of the given browser. @BeforeTest public void browserlaunch() { driver = Browser.StartBrowser('Chrome', 'http://demostore.kenticolab.com/Special-Pages/Logon.aspx'); driver.manage().timeouts().implicitlyWait(30,TimeUnit. SECONDS ); lp = new LoginPage(driver); hp = new HomePage(driver); } // Login to the Site. @Test(priority = 1) public void Login() { lp.loginToSite('gaurav.3n@gmail.com','Test@123'); } // Verifing the Home Page. @Test(priority = 2) public void HomePageVerify() { String HomeText = hp.pageverify(); Assert.assertEquals(HomeText, 'Logged on as'); } // Logout the site. @Test(priority = 3) public void Logout() { hp.logout(); } // Taking Screen shot on test fail @AfterMethod public void screenshot(ITestResult result) { i = i+1; String name = 'ScreenShot'; String x = name+String.valueOf(i); if (ITestResult. FAILURE == result.getStatus()) { ScreenShot.captureScreenShot(driver, x); } } @AfterTest public void closeBrowser() { driver.close(); } }
Étape 5: Exécutez «LoginTestCase.java».
Étape 6: Sortie du modèle d'objet de page:
- Lancez le navigateur Chrome.
- Le site Web de démonstration s'ouvre dans le navigateur.
- Connectez-vous au site de démonstration.
- Vérifiez la page d'accueil.
- Déconnectez-vous du site.
- Fermez le navigateur.
Maintenant, explorons le concept principal de ce tutoriel qui attire l'attention, c'est-à-dire «Pagefactory».
Qu'est-ce que Pagefactory?
PageFactory est une manière d'implémenter le «modèle d'objet de page». Ici, nous suivons le principe de la séparation du référentiel d'objets de page et des méthodes de test. C'est un concept intégré de modèle d'objet de page qui est très optimisé.
Ayons maintenant plus de clarté sur le terme Pagefactory.
#1) Premièrement, le concept appelé Pagefactory, fournit une autre manière en termes de syntaxe et de sémantique pour créer un référentiel d'objets pour les éléments Web sur une page.
#deux) Deuxièmement, il utilise une stratégie légèrement différente pour l'initialisation des éléments Web.
# 3) Le référentiel d'objets pour les éléments Web de l'interface utilisateur peut être créé en utilisant:
- «POM sans Pagefactory» habituel et,
- Vous pouvez également utiliser «POM avec Pagefactory».
Ci-dessous est une représentation picturale de la même chose:
Nous allons maintenant examiner tous les aspects qui différencient le POM habituel du POM avec Pagefactory.
a) La différence dans la syntaxe de localisation d'un élément en utilisant POM habituel vs POM avec Pagefactory.
Par exemple , Cliquez sur ici pour localiser le champ de recherche qui apparaît sur la page.
POM sans Pagefactory:
# 1) Voici comment localiser le champ de recherche en utilisant le POM habituel:
WebElement searchNSETxt=driver.findElement(By.id(“searchBox”));
# 2) L'étape ci-dessous transmet la valeur «investissement» dans le champ Recherche NSE.
searchNSETxt.sendkeys(“investment”);
POM utilisant Pagefactory:
#1) Vous pouvez localiser le champ de recherche en utilisant Pagefactory comme indiqué ci-dessous.
L'annotation @FindBy est utilisé dans Pagefactory pour identifier un élément tandis que POM sans Pagefactory utilise le driver.findElement () méthode pour localiser un élément.
La deuxième déclaration pour Pagefactory après @FindBy affecte un type WebElement classe qui fonctionne exactement comme l'attribution d'un nom d'élément de type classe WebElement comme type de retour de la méthode driver.findElement () qui est utilisé dans le POM habituel (searchNSETxt dans cet exemple).
Nous examinerons le @FindBy annotations en détail dans la partie à venir de ce didacticiel.
@FindBy(id = 'searchBox') WebElement searchNSETxt;
#deux) L'étape ci-dessous passe la valeur «investissement» dans le champ Recherche NSE et la syntaxe reste la même que celle du POM habituel (POM sans Pagefactory).
searchNSETxt.sendkeys(“investment”);
b) La différence dans la stratégie d'initialisation des éléments Web en utilisant POM habituel vs POM avec Pagefactory.
Utilisation de POM sans Pagefactory:
Vous trouverez ci-dessous un extrait de code pour définir le chemin du pilote Chrome. Une instance WebDriver est créée avec le nom du pilote et le ChromeDriver est attribué au «pilote». Le même objet pilote est ensuite utilisé pour lancer le site Web de la Bourse nationale, localiser le searchBox et entrer la valeur de la chaîne dans le champ.
Le point que je souhaite souligner ici est que lorsqu'il s'agit d'un POM sans fabrique de pages, l'instance de pilote est créée initialement et chaque élément Web est fraîchement initialisé à chaque fois qu'il y a un appel à cet élément Web à l'aide de driver.findElement () ou driver .findElements ().
C'est pourquoi, avec une nouvelle étape de driver.findElement () pour un élément, la structure DOM est à nouveau parcourue et l'identification actualisée de l'élément est effectuée sur cette page.
System.setProperty('webdriver.chrome.driver', 'C:\eclipse-workspace\automationframework\src\test\java\Drivers\chromedriver.exe'); WebDriver driver = new ChromeDriver(); driver.get('http://www.nseindia.com/'); WebElement searchNSETxt=driver.findElement(By.id(“searchBox”)); searchNSETxt.sendkeys(“investment”);
Utilisation de POM avec Pagefactory:
Outre l'utilisation de l'annotation @FindBy au lieu de la méthode driver.findElement (), l'extrait de code ci-dessous est également utilisé pour Pagefactory. La méthode statique initElements () de la classe PageFactory est utilisée pour initialiser tous les éléments de l'interface utilisateur de la page dès que la page se charge.
public PagefactoryClass(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); }
La stratégie ci-dessus rend l'approche PageFactory légèrement différente du POM habituel. Dans le POM habituel, l'élément Web doit être explicitement initialisé tandis que dans l'approche Pagefactory tous les éléments sont initialisés avec initElements () sans initialiser explicitement chaque élément Web.
Par exemple: Si le WebElement a été déclaré mais pas initialisé dans le POM habituel, alors l'erreur «initialize variable» ou NullPointerException est émise. Par conséquent, dans le POM habituel, chaque WebElement doit être explicitement initialisé. Dans ce cas, PageFactory présente un avantage sur le POM habituel.
Ne initialisons pas l'élément web BDate (POM sans Pagefactory), vous pouvez voir que l'erreur 'Initialiser la variable' s'affiche et invite l'utilisateur à l'initialiser à null, par conséquent, vous ne pouvez pas supposer que les éléments sont initialisés implicitement lors de leur localisation.
Élément BDate explicitement initialisé (POM sans Pagefactory):
Examinons maintenant quelques exemples d'un programme complet utilisant PageFactory pour exclure toute ambiguïté dans la compréhension de l'aspect implémentation.
Exemple 1:
- Accédez à «http://www.nseindia.com/»
- Dans la liste déroulante à côté du champ de recherche, sélectionnez 'Dérivés de devises'.
- Recherchez «USDINR». Vérifiez le texte 'Dollar américain-Roupie indienne - USDINR' sur la page qui s'affiche.
Structure du programme:
- PagefactoryClass.java qui inclut un référentiel d'objets utilisant le concept de fabrique de pages pour nseindia.com qui est un constructeur pour l'initialisation de tous les éléments Web est créé, la méthode selectCurrentDerivative () pour sélectionner une valeur dans le champ déroulant Searchbox, selectSymbol () pour sélectionner un symbole sur le page qui apparaît ensuite et verifytext () pour vérifier si l'en-tête de la page est comme prévu ou non.
- NSE_MainClass.java est le fichier de classe principal qui appelle toutes les méthodes ci-dessus et exécute les actions respectives sur le site NSE.
PagefactoryClass.java
package com.pagefactory.knowledge; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; import org.openqa.selenium.support.ui.Select; public class PagefactoryClass { WebDriver driver; @FindBy(id = 'QuoteSearch') WebElement Searchbox; @FindBy(id = 'cidkeyword') WebElement Symbol; @FindBy(id = 'companyName') WebElement pageText; public PagefactoryClass(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); } public void selectCurrentDerivative(String derivative) { Select select = new Select(Searchbox); select.selectByVisibleText(derivative); // 'Currency Derivatives' } public void selectSymbol(String symbol) { Symbol.sendKeys(symbol); } public void verifytext() { if (pageText.getText().equalsIgnoreCase('U S Dollar-Indian Rupee - USDINR')) { System.out.println('Page Header is as expected'); } else System.out.println('Page Header is NOT as expected'); } }
NSE_MainClass.java
package com.pagefactory.knowledge; import java.util.List; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.StaleElementReferenceException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; public class NSE_MainClass { static PagefactoryClass page; static WebDriver driver; public static void main(String() args) { System.setProperty('webdriver.chrome.driver', 'C:\Users\eclipse-workspace\automation-framework\src\test\java\Drivers\chromedriver.exe'); driver = new ChromeDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.get('https://www.nseindia.com/'); driver.manage().window().maximize(); test_Home_Page_ofNSE(); } public static void test_Home_Page_ofNSE() throws StaleElementReferenceException { page = new PagefactoryClass(driver); page.selectCurrentDerivative('Currency Derivatives'); page.selectSymbol('USD'); List Options = driver.findElements(By.xpath('//span(contains(.,'USD'))')); int count = Options.size(); for (int i = 0; i Exemple 2:
- Accédez à «https://www.shoppersstop.com/brands»
- Accédez au lien Haute curry.
- Vérifiez si la page Haute Curry contient le texte «Start New Something».
Structure du programme
- shopperstopPagefactory.java qui inclut un référentiel d'objets utilisant le concept pagefactory pour shoppersstop.com qui est un constructeur pour l'initialisation de tous les éléments Web est créé, les méthodes closeExtraPopup () pour gérer une fenêtre contextuelle d'alerte qui s'ouvre, cliquez surOnHauteCurryLink () pour cliquer sur Haute Curry Liez et verifyStartNewSomething () pour vérifier si la page Haute Curry contient le texte «Commencer quelque chose».
- Shopperstop_CallPagefactory.java est le fichier de classe principal qui appelle toutes les méthodes ci-dessus et effectue les actions respectives sur le site NSE.
shopperstopPagefactory.java
package com.inportia.automation_framework; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class shopperstopPagefactory { WebDriver driver; @FindBy(id='firstVisit') WebElement extrapopup; @FindBy(xpath='//img(@src='https://sslimages.shoppersstop.com /sys-master/root/haf/h3a/9519787376670/brandMedia_HauteCurry_logo.png')') WebElement HCLink; @FindBy(xpath='/html/body/main/footer/div(1)/p') WebElement Startnew; public shopperstopPagefactory(WebDriver driver) { this.driver=driver; PageFactory.initElements(driver, this); } public void closeExtraPopup() { extrapopup.click(); } public void clickOnHauteCurryLink() { JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript('arguments(0).click();',HCLink); js.executeAsyncScript('window.setTimeout(arguments(arguments.length - 1), 10000);'); if(driver.getCurrentUrl().equals('https://www.shoppersstop.com/haute-curry')) { System.out.println('We are on the Haute Curry page'); } else { System.out.println('We are NOT on the Haute Curry page'); } } public void verifyStartNewSomething() { if (Startnew.getText().equalsIgnoreCase('Start Something New')) { System.out.println('Start new something text exists'); } else System.out.println('Start new something text DOESNOT exists'); } }
Shopperstop_CallPagefactory.java
package com.inportia.automation_framework; import java.util.concurrent.TimeUnit; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; public class Shopperstop_CallPagefactory extends shopperstopPagefactory { public Shopperstop_CallPagefactory(WebDriver driver) { super(driver); // TODO Auto-generated constructor stub } static WebDriver driver; public static void main(String() args) { System.setProperty('webdriver.chrome.driver', 'C:\eclipse-workspace\automation-framework\src\test\java\Drivers\chromedriver.exe'); driver = new ChromeDriver(); Shopperstop_CallPagefactory s1=new Shopperstop_CallPagefactory(driver); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.get('https://www.shoppersstop.com/brands'); s1.clickOnHauteCurryLink(); s1.verifyStartNewSomething(); } }
POM utilisant Page Factory
Tutoriels vidéo - POM avec Page Factory
Partie I
Partie II
Une classe Factory est utilisée pour simplifier et simplifier l'utilisation des objets de page.
- Tout d'abord, nous devons trouver les éléments Web par annotation @FindBy dans les classes de page .
- Ensuite, initialisez les éléments à l'aide de initElements () lors de l'instanciation de la classe de page.
#1) @FindBy:
L'annotation @FindBy est utilisée dans PageFactory pour localiser et déclarer les éléments Web à l'aide de différents localisateurs.Ici, nous transmettons l'attribut ainsi que sa valeur utilisée pour localiser l'élément Web à l'annotation @FindBy, puis le WebElement est déclaré.
L'annotation peut être utilisée de deux manières.
Par exemple:
@FindBy(how = How.ID, using='EmailAddress') WebElement Email; @FindBy(id='EmailAddress') WebElement Email;
Cependant, le premier est la méthode standard de déclaration des WebElements.
'Comment' est une classe et elle a des variables statiques comme ID, XPATH, CLASSNAME, LINKTEXT, etc.
'utilisant' - Pour affecter une valeur à une variable statique.
Au dessus exemple , nous avons utilisé l'attribut 'id' pour localiser l'élément Web 'Email'. De même, nous pouvons utiliser les localisateurs suivants avec les annotations @FindBy:
- nom du cours
- css
- Nom
- xpath
- tagName
- linkText
- partialLinkText
# 2) initElements ():
L'initElements est une méthode statique de la classe PageFactory qui est utilisée pour initialiser tous les éléments Web localisés par l'annotation @FindBy. Ainsi, instancier facilement les classes Page.
initElements(WebDriver driver, java.lang.Class pageObjectClass)
Nous devons également comprendre que POM suit les principes OOPS.
- Les WebElements sont déclarés en tant que variables membres privées (masquage de données).
- Liaison des WebElements avec les méthodes correspondantes (Encapsulation).
Étapes pour créer un POM à l'aide d'un modèle de fabrique de pages
#1) Créez un fichier de classe Java distinct pour chaque page Web.
#deux) Dans chaque classe, tous les WebElements doivent être déclarés en tant que variables (en utilisant l'annotation - @FindBy) et initialisés en utilisant la méthode initElement (). Les WebElements déclarés doivent être initialisés pour être utilisés dans les méthodes d'action.
# 3) Définissez les méthodes correspondantes agissant sur ces variables.
Prenons un exemple de scénario simple:
- Ouvrez l'URL d'une application.
- Saisissez l'adresse e-mail et le mot de passe.
- Cliquez sur le bouton Connexion.
- Vérifiez le message de connexion réussi sur la page de recherche.
Couche de page
Ici nous avons 2 pages,
- Page d'accueil - La page qui s'ouvre lorsque l'URL est saisie et où nous saisissons les données pour la connexion.
- RecherchePage - Une page qui s'affiche après une connexion réussie.
Dans la couche de page, chaque page de l'application Web est déclarée en tant que classe Java distincte et ses localisateurs et actions y sont mentionnés.
Étapes pour créer un POM avec un exemple en temps réel
# 1) Créez une classe Java pour chaque page:
Dans ce exemple , nous accèderons à 2 pages Web, les pages «Accueil» et «Recherche».
Par conséquent, nous allons créer 2 classes Java dans Page Layer (ou dans un package, disons com.automation.pages).
Package Name :com.automation.pages HomePage.java SearchPage.java
# 2) Définissez les WebElements en tant que variables en utilisant Annotation @FindBy:
Nous interagirions avec:
- Courriel, mot de passe, champ du bouton de connexion sur la page d'accueil.
- Message réussi sur la page de recherche.
Nous allons donc définir les WebElements en utilisant @FindBy
Par exemple: Si nous allons identifier EmailAddress à l'aide de l'ID d'attribut, sa déclaration de variable est
//Locator for EmailId field @FindBy(how=How.ID,using='EmailId') private WebElementEmailIdAddress;
# 3) Créez des méthodes pour les actions effectuées sur WebElements.
Les actions ci-dessous sont effectuées sur WebElements:
- Saisissez une action dans le champ Adresse e-mail.
- Saisissez une action dans le champ Mot de passe.
- Cliquez sur l'action sur le bouton de connexion.
Par exemple, Les méthodes définies par l'utilisateur sont créées pour chaque action sur le WebElement comme suit:
public void typeEmailId(String Id){ driver.findElement(EmailAddress).sendKeys(Id) }
Ici, l'ID est passé en paramètre dans la méthode, car l'entrée sera envoyée par l'utilisateur à partir du scénario de test principal.
Remarque :Un constructeur doit être créé dans chacune des classes de la couche de page, afin d'obtenir l'instance de pilote de la classe Main dans la couche de test et également d'initialiser les WebElements (objets de page) déclarés dans la classe de page à l'aide de PageFactory.InitElement () .
Nous n'initions pas le pilote ici, mais son instance est reçue de la classe principale lorsque l'objet de la classe Page Layer est créé.
InitElement () - est utilisé pour initialiser les WebElements déclarés, en utilisant l'instance de pilote de la classe principale. En d'autres termes, les WebElements sont créés à l'aide de l'instance de pilote. Ce n'est qu'après l'initialisation des WebElements qu'ils peuvent être utilisés dans les méthodes pour effectuer des actions.
Deux classes Java sont créées pour chaque page, comme indiqué ci-dessous:
HomePage.java
//package com.automation.pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class HomePage { WebDriver driver; // Locator for Email Address @FindBy(how=How.ID,using='EmailId') private WebElement EmailIdAddress; // Locator for Password field @FindBy(how=How.ID,using='Password ') private WebElement Password; // Locator for SignIn Button @FindBy(how=How.ID,using='SignInButton') private WebElement SignInButton; // Method to type EmailId public void typeEmailId(String Id){ driver.findElement(EmailAddress).sendKeys(Id) } // Method to type Password public void typePassword(String PasswordValue){ driver.findElement(Password).sendKeys(PasswordValue) } // Method to click SignIn Button public void clickSignIn(){ driver.findElement(SignInButton).click() } // Constructor // Gets called when object of this page is created in MainClass.java public HomePage(WebDriver driver) { // 'this' keyword is used here to distinguish global and local variable 'driver' //gets driver as parameter from MainClass.java and assigns to the driver instance in this class this.driver=driver; PageFactory.initElements(driver,this); // Initialises WebElements declared in this class using driver instance. } }
SearchPage.Java
//package com.automation.pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class SearchPage{ WebDriver driver; // Locator for Success Message @FindBy(how=How.ID,using='Message') private WebElement SuccessMessage; // Method that return True or False depending on whether the message is displayed public Boolean MessageDisplayed(){ Boolean status = driver.findElement(SuccessMessage).isDisplayed(); return status; } // Constructor // This constructor is invoked when object of this page is created in MainClass.java public SearchPage(WebDriver driver) { // 'this' keyword is used here to distinguish global and local variable 'driver' //gets driver as parameter from MainClass.java and assigns to the driver instance in this class this.driver=driver; PageFactory.initElements(driver,this); // Initialises WebElements declared in this class using driver instance. } }
Couche de test
Les cas de test sont implémentés dans cette classe. Nous créons un package séparé, disons com.automation.test, puis créons une classe Java ici (MainClass.java)
Étapes pour créer des scénarios de test:
- Initialisez le pilote et ouvrez l'application.
- Créez un objet de la classe PageLayer (pour chaque page Web) et transmettez l'instance de pilote en tant que paramètre.
- À l'aide de l'objet créé, appelez les méthodes de la classe PageLayer (pour chaque page Web) afin d'effectuer des actions / vérification.
- Répétez l'étape 3 jusqu'à ce que toutes les actions soient effectuées, puis fermez le pilote.
//package com.automation.test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; public class MainClass { public static void main(String() args) { System.setProperty('webdriver.chrome.driver','./exefiles/chromedriver.exe'); WebDriver driver= new ChromeDriver(); driver.manage().window().maximize(); driver.get('URL mentioned here'); // Creating object of HomePage and driver instance is passed as parameter to constructor of Homepage.Java HomePage homePage= new HomePage(driver); // Type EmailAddress homePage.typeEmailId('abc@ymail.com'); // EmailId value is passed as paramter which in turn will be assigned to the method in HomePage.Java // Type Password Value homePage.typePassword('password123'); // Password value is passed as paramter which in turn will be assigned to the method in HomePage.Java // Click on SignIn Button homePage.clickSignIn(); // Creating an object of LoginPage and driver instance is passed as parameter to constructor of SearchPage.Java SearchPage searchPage= new SearchPage(driver); //Verify that Success Message is displayed Assert.assertTrue(searchPage.MessageDisplayed()); //Quit browser driver.quit(); } }
Hiérarchie des types d'annotations utilisée pour déclarer des éléments Web
Les annotations sont utilisées pour aider à construire une stratégie de localisation pour les éléments de l'interface utilisateur.
# 1) @FindBy
Quand il s'agit de Pagefactory, @FindBy agit comme une baguette magique. Cela ajoute toute la puissance au concept. Vous savez maintenant que l'annotation @FindBy dans Pagefactory fonctionne de la même manière que celle de driver.findElement () dans le modèle d'objet de page habituel. Il est utilisé pour localiser WebElement / WebElements avec un critère .
# 2) @FindBys
Il est utilisé pour localiser WebElement avec plus d'un critère et doivent correspondre à tous les critères donnés. Ces critères doivent être mentionnés dans une relation parent-enfant. En d'autres termes, cela utilise la relation conditionnelle ET pour localiser les WebElements à l'aide des critères spécifiés. Il utilise plusieurs @FindBy pour définir chaque critère.
Par exemple:
Code source HTML d'un WebElement:
Dans POM:
@FindBys({ @FindBy(id = 'searchId_1'), @FindBy(name = 'search_field') }) WebElementSearchButton;
Dans l'exemple ci-dessus, le WebElement ‘SearchButton’ est localisé uniquement s'il correspond aux deux les critères dont la valeur d'id est «searchId_1» et la valeur de nom est «search_field». Veuillez noter que les premiers critères appartiennent à une balise parent et les seconds à une balise enfant.
# 3) @FindAll
Il est utilisé pour localiser WebElement avec plus d'un critère et il doit correspondre à au moins un des critères donnés. Cela utilise des relations conditionnelles OR afin de localiser les WebElements. Il utilise plusieurs @FindBy pour définir tous les critères.
Par exemple:
Code source HTML:
Dans POM:
@FindBys({ @FindBy(id = 'UsernameNameField_1'), // doesn’t match @FindBy(name = 'User_Id') //matches @FindBy(className = “UserName_r”) //matches }) WebElementUserName;
Dans l'exemple ci-dessus, le nom d'utilisateur WebElement est localisé s'il correspond à au moins un des critères mentionnés.
# 4) @CacheLookUp
Lorsque le WebElement est plus souvent utilisé dans les cas de test, Selenium recherche le WebElement à chaque fois que le script de test est exécuté. Dans ces cas, certains WebElements sont globalement utilisés pour tous les TC ( Par exemple, Le scénario de connexion se produit pour chaque TC), cette annotation peut être utilisée pour maintenir ces WebElements dans la mémoire cache une fois qu'ils sont lus pour la première fois.
Ceci, à son tour, aide le code à s’exécuter plus rapidement car à chaque fois, il n’a pas à rechercher le WebElement dans la page, mais il peut obtenir sa référence à partir de la mémoire.
Cela peut être comme un préfixe avec l'un des @FindBy, @FindBys et @FindAll.
Par exemple:
@CacheLookUp @FindBys({ @FindBy(id = 'UsernameNameField_1'), @FindBy(name = 'User_Id') @FindBy(className = “UserName_r”) }) WebElementUserName;
Notez également que cette annotation ne doit être utilisée que pour les WebElements dont la valeur d'attribut (comme xpath, nom d'id, nom de classe, etc.) ne change pas assez souvent. Une fois le WebElement localisé pour la première fois, il conserve sa référence dans la mémoire cache.
Ainsi, il se produit un changement dans l’attribut de WebElement après quelques jours, Selenium ne pourra pas localiser l’élément, car il a déjà son ancienne référence dans sa mémoire cache et ne tiendra pas compte du changement récent de WebElement.
Plus sur PageFactory.initElements ()
Maintenant que nous comprenons la stratégie de Pagefactory sur l'initialisation des éléments Web à l'aide d'InitElements (), essayons de comprendre les différentes versions de la méthode.
La méthode que nous connaissons prend l'objet pilote et l'objet de classe actuel comme paramètres d'entrée et retourne l'objet de page en initialisant implicitement et proactivement tous les éléments de la page.
En pratique, l'utilisation du constructeur comme indiqué dans la section ci-dessus est plus préférable aux autres modes d'utilisation.
Les autres façons d'appeler la méthode sont:
#1) Au lieu d'utiliser le pointeur «this», vous pouvez créer l'objet de classe actuel, lui passer l'instance de pilote et appeler la méthode statique initElements avec des paramètres, c'est-à-dire l'objet pilote et l'objet de classe qui vient d'être créé.
public PagefactoryClass(WebDriver driver) { //version 2 PagefactoryClass page=new PagefactoryClass(driver); PageFactory.initElements(driver, page); }
#deux) La troisième façon d'initialiser des éléments à l'aide de la classe Pagefactory consiste à utiliser l'API appelée «reflet». Oui, au lieu de créer un objet de classe avec un mot clé «new», classname.class peut être passé dans le cadre du paramètre d'entrée initElements ().
public PagefactoryClass(WebDriver driver) { //version 3 PagefactoryClass page=PageFactory.initElements(driver, PagefactoryClass.class); }
Questions fréquemment posées
Q # 1) Quelles sont les différentes stratégies de localisation utilisées pour @FindBy?
Répondre: La réponse simple à cela est qu'il n'y a pas de stratégies de localisation différentes utilisées pour @FindBy.
Ils utilisent les 8 mêmes stratégies de localisation que la méthode findElement () dans le POM habituel utilise:
- identifiant
- Nom
- nom du cours
- xpath
- css
- tagName
- linkText
- partialLinkText
Q # 2) Existe-t-il également différentes versions de l'utilisation des annotations @FindBy?
Répondre: Lorsqu'il y a un élément Web à rechercher, nous utilisons l'annotation @FindBy. Nous développerons également les différentes manières d'utiliser @FindBy ainsi que les différentes stratégies de localisation.
Nous avons déjà vu comment utiliser la version 1 de @FindBy:
@FindBy(id = 'cidkeyword') WebElement Symbol;
La version 2 de @FindBy consiste à transmettre le paramètre d'entrée comme Comment et Utilisant .
Comment recherche la stratégie de localisation à l'aide de laquelle le webelement serait identifié. Le mot clé utilisant définit la valeur du localisateur.
Voir ci-dessous pour une meilleure compréhension,
- How.ID recherche l'élément en utilisant identifiant stratégie et l'élément qu'il tente d'identifier a id = cidkeyword.
@FindBy(how = How.ID, using = ' cidkeyword') WebElement Symbol;
- Comment.CLASS_NAME recherche l'élément à l'aide de nom du cours stratégie et l'élément qu'il tente d'identifier a class = newclass.
@FindBy(how = How.CLASS_NAME, using = 'newclass') WebElement Symbol;
Q # 3) Y a-t-il une différence entre les deux versions de @FindBy?
Répondre: La réponse est non, il n'y a aucune différence entre les deux versions. C'est juste que la première version est la plus courte et la plus facile par rapport à la deuxième version.
Q # 4) Que dois-je utiliser dans la pagefactory au cas où il y aurait une liste d'éléments Web à localiser?
Répondre: Dans le modèle de conception d'objet de page habituel, nous avons driver.findElements () pour localiser plusieurs éléments appartenant à la même classe ou au même nom de balise, mais comment localiser ces éléments dans le cas d'un modèle d'objet de page avec Pagefactory? Le moyen le plus simple d'obtenir de tels éléments est d'utiliser la même annotation @FindBy.
Je comprends que cette ligne semble être un casse-tête pour beaucoup d'entre vous. Mais oui, c'est la réponse à la question.
Regardons l'exemple ci-dessous:
En utilisant le modèle d'objet de page habituel sans Pagefactory, vous utilisez driver.findElements pour localiser plusieurs éléments comme indiqué ci-dessous:
private List multipleelements_driver_findelements = driver.findElements (By.class(“last”));
La même chose peut être obtenue en utilisant le modèle d'objet de page avec Pagefactory comme indiqué ci-dessous:
@FindBy (how = How.CLASS_NAME, using = 'last') private List multipleelements_FindBy;
Fondamentalement, l'affectation des éléments à une liste de type WebElement fait l'affaire indépendamment du fait que Pagefactory a été utilisé ou non lors de l'identification et de la localisation des éléments.
Q # 5) Est-ce que la conception d'objet de page sans pagefactory et avec Pagefactory peut être utilisée dans le même programme?
Répondre: Oui, la conception d'objet de page sans Pagefactory et avec Pagefactory peut être utilisée dans le même programme. Vous pouvez suivre le programme ci-dessous dans le Réponse à la question 6 pour voir comment les deux sont utilisés dans le programme.
Une chose à retenir est que le concept Pagefactory avec la fonctionnalité mise en cache doit être évité sur les éléments dynamiques alors que la conception d'objet de page fonctionne bien pour les éléments dynamiques. Cependant, Pagefactory ne convient qu'aux éléments statiques.
Q # 6) Existe-t-il d'autres façons d'identifier les éléments en fonction de plusieurs critères?
quel est le plan de test dans les tests logiciels
Répondre: L'alternative pour identifier les éléments en fonction de plusieurs critères consiste à utiliser les annotations @FindAll et @FindBys. Ces annotations aident à identifier les éléments uniques ou multiples en fonction des valeurs extraites des critères qui y sont passés.
# 1) @FindAll:
@FindAll peut contenir plusieurs @FindBy et renverra tous les éléments qui correspondent à n'importe quel @FindBy dans une seule liste. @FindAll est utilisé pour marquer un champ sur un objet de page pour indiquer que la recherche doit utiliser une série de balises @FindBy. Il recherchera ensuite tous les éléments qui correspondent à l'un des critères FindBy.
Notez que les éléments ne sont pas garantis d'être dans l'ordre du document.
La syntaxe à utiliser @FindAll est la suivante:
@FindAll( { @FindBy(how = How.ID, using = 'foo'), @FindBy(className = 'bar') } )
Explication: @FindAll recherchera et identifiera des éléments séparés conformes à chacun des critères @FindBy et les listera. Dans l'exemple ci-dessus, il recherchera d'abord un élément dont l'id = 'foo', puis identifiera le deuxième élément avec className = 'bar'.
En supposant qu'il y avait un élément identifié pour chaque critère FindBy, @FindAll entraînera la liste de 2 éléments, respectivement. N'oubliez pas que plusieurs éléments peuvent être identifiés pour chaque critère. Ainsi, en termes simples, @ Trouver tout actes équivalents au OU opérateur sur les critères @FindBy passés.
# 2) @FindBys:
FindBys est utilisé pour marquer un champ sur un objet de page pour indiquer que la recherche doit utiliser une série de balises @FindBy dans une chaîne comme décrit dans ByChained. Lorsque les objets WebElement requis doivent correspondre à tous les critères donnés, utilisez l'annotation @FindBys.
La syntaxe à utiliser @FindBys est la suivante:
@FindBys( { @FindBy(name=”foo”) @FindBy(className = 'bar') } )
Explication: @FindBys recherchera et identifiera les éléments conformes à tous les critères @FindBy et les listera. Dans l'exemple ci-dessus, il recherchera les éléments dont le nom = 'foo' et className = 'bar'.
@FindAll aboutira à lister 1 élément si nous supposons qu'il y avait un élément identifié avec le nom et le className dans les critères donnés.
S'il n'y a pas un élément satisfaisant toutes les conditions FindBy passées, alors la résultante de @FindBys sera zéro élément. Il pourrait y avoir une liste d'éléments Web identifiés si toutes les conditions satisfont plusieurs éléments. En termes simples, @ FindBys actes équivalents au ET opérateur sur les critères @FindBy passés.
Voyons la mise en œuvre de toutes les annotations ci-dessus à travers un programme détaillé:
Nous modifierons le programme www.nseindia.com donné dans la section précédente pour comprendre l'implémentation des annotations @FindBy, @FindBys et @FindAll
# 1) Le référentiel d'objets de PagefactoryClass est mis à jour comme ci-dessous:
List newlist = driver.findElements (By.tagName ('a'));
@FindBy (comment = comment. TAG_NAME , en utilisant = 'a')
privé Liste findbyvalue;
@Trouver tout ({ @FindBy (className = 'sel'), @FindBy (xpath = ”// a (@ id =’ tab5 ′) ”)})
privé Liste findallvalue;
@FindBys ({ @FindBy (className = 'sel'), @FindBy (xpath = ”// a (@ id =’ tab5 ′) ”)})
privé Liste findbysvalue;
# 2) Une nouvelle méthode seeHowFindWorks () est écrite dans PagefactoryClass et est appelée comme dernière méthode de la classe Main.
La méthode est la suivante:
private void seeHowFindWorks() { System.out.println('driver.findElements(By.tagName()) '+newlist.size()); System.out.println('count of @FindBy- list elements '+findbyvalue.size()); System.out.println('count of @FindAll elements '+findallvalue.size()); for(int i=0;i Ci-dessous, le résultat affiché sur la fenêtre de la console après l'exécution du programme:
Essayons maintenant de comprendre le code en détail:
#1) Grâce au modèle de conception de l'objet de page, l'élément «nouvelle liste» identifie toutes les balises avec l'ancre «a». En d'autres termes, nous obtenons un décompte de tous les liens sur la page.
Nous avons appris que la pagefactory @FindBy fait le même travail que celle de driver.findElement (). L'élément findbyvalue est créé pour obtenir le décompte de tous les liens sur la page grâce à une stratégie de recherche ayant un concept pagefactory.
Cela prouve que driver.findElement () et @FindBy font le même travail et identifient les mêmes éléments. Si vous regardez la capture d'écran de la fenêtre de console résultante ci-dessus, le nombre de liens identifiés avec l'élément newlist et celui de findbyvalue sont égaux, c'est-à-dire 299 liens trouvés sur la page.
Le résultat a montré comme ci-dessous:
driver.findElements(By.tagName()) 299 count of @FindBy- list elements 299
#deux) Ici, nous développons le fonctionnement de l'annotation @FindAll qui appartiendra à la liste des éléments Web avec le nom findallvalue.
En examinant attentivement chaque critère @FindBy dans l'annotation @FindAll, le premier critère @FindBy recherche les éléments avec le className = 'sel' et le deuxième critère @FindBy recherche un élément spécifique avec XPath = '// a (@ id = 'tab5')
Appuyez maintenant sur F12 pour inspecter les éléments de la page nseindia.com et obtenir certaines précisions sur les éléments correspondant aux critères @FindBy.
Il y a deux éléments sur la page correspondant au className = 'sel':
à) L'élément «Fundamentals» a la balise list, c'est-à-dire
avec className = 'sel'. Voir l'instantané ci-dessous
b) Un autre élément 'Order Book' a un XPath avec une balise d'ancrage dont le nom de classe est 'sel'.
c) Le deuxième @FindBy avec XPath a une balise d'ancrage dont identifiant est ' tab5 ». Il n'y a qu'un seul élément identifié en réponse à la recherche qui est Fundamentals.
Voir l'instantané ci-dessous:
Lorsque le test nseindia.com a été exécuté, nous avons obtenu le nombre d'éléments recherchés par.
@FindAll as 3. Les éléments de findallvalue lors de l'affichage étaient: Fundamentals as the 0eélément d'index, Carnet de commandes comme 1stélément d'index et fondamentaux à nouveau en tant que 2ndélément d'index. Nous avons déjà appris que @FindAll identifie les éléments pour chaque critère @FindBy séparément.
Selon le même protocole, pour la recherche du premier critère, c'est-à-dire className = 'sel', il a identifié deux éléments satisfaisant à la condition et il a récupéré 'Fundamentals' et 'Order Book'.
Ensuite, il est passé au critère @FindBy suivant et, selon le xpath donné pour le deuxième @FindBy, il pourrait récupérer l'élément «Fundamentals». C'est pourquoi, il a finalement identifié 3 éléments, respectivement.
Ainsi, il n'obtient pas les éléments satisfaisant à l'une ou l'autre des conditions @FindBy, mais il traite séparément chacun des @FindBy et identifie les éléments de la même manière. De plus, dans l'exemple actuel, nous avons également vu qu'il ne vérifie pas si les éléments sont uniques ( Par exemple. L'élément «Fundamentals» dans ce cas qui s'affiche deux fois dans le cadre du résultat des deux critères @FindBy)
# 3) Nous développons ici le fonctionnement de l'annotation @FindBys qui appartiendra à la liste des éléments Web avec le nom findbysvalue. Ici aussi, le premier critère @FindBy recherche les éléments avec le className = 'sel' et le second critère @FindBy recherche un élément spécifique avec xpath = “// a (@ id =” tab5 ”).
Maintenant que nous le savons, les éléments identifiés pour la première condition @FindBy sont «Fundamentals» et «Order Book» et celui du deuxième critère @FindBy est «Fundamentals».
Alors, comment le résultat @FindBys va-t-il être différent de @FindAll? Nous avons appris dans la section précédente que @FindBys est équivalent à l'opérateur conditionnel AND et par conséquent, il recherche un élément ou la liste d'éléments qui satisfait toutes les conditions @FindBy.
Comme dans notre exemple actuel, la valeur 'Fundamentals' est le seul élément qui a class = 'sel' et id = 'tab5', satisfaisant ainsi les deux conditions. C'est pourquoi la taille de @FindBys dans le testcase est 1 et affiche la valeur comme «Fondamentaux».
Mise en cache des éléments dans Pagefactory
Chaque fois qu'une page est chargée, tous les éléments de la page sont à nouveau recherchés en appelant un appel via @FindBy ou driver.findElement () et il y a une nouvelle recherche des éléments sur la page.
La plupart du temps, lorsque les éléments sont dynamiques ou continuent de changer pendant l'exécution, en particulier s'il s'agit d'éléments AJAX, il est certainement logique qu'à chaque chargement de page, il y ait une nouvelle recherche pour tous les éléments de la page.
Lorsque la page Web contient des éléments statiques, la mise en cache de l'élément peut aider de plusieurs manières. Lorsque les éléments sont mis en cache, il n'est pas nécessaire de les localiser à nouveau lors du chargement de la page, mais il peut référencer le référentiel des éléments mis en cache. Cela fait gagner beaucoup de temps et améliore les performances.
Pagefactory fournit cette fonctionnalité de mise en cache des éléments à l'aide d'une annotation @CacheLookUp .
L'annotation indique au pilote d'utiliser la même instance du localisateur du DOM pour les éléments et de ne pas les rechercher à nouveau tandis que la méthode initElements de la pagefactory contribue de manière proéminente au stockage de l'élément statique mis en cache. Les initElements font le travail de mise en cache des éléments.
Cela rend le concept de pagefactory spécial par rapport au modèle de conception d'objet de page normal. Il a ses propres avantages et inconvénients dont nous parlerons un peu plus tard. Par exemple, le bouton de connexion sur la page d'accueil Facebook est un élément statique, qui peut être mis en cache et est un élément idéal à mettre en cache.
Voyons maintenant comment implémenter l'annotation @CacheLookUp
Vous devrez d'abord importer un package pour Cachelookup comme ci-dessous:
import org.openqa.selenium.support.CacheLookup
Voici l'extrait de code affichant la définition d'un élément à l'aide de @CacheLookUp. Dès que le UniqueElement est recherché pour la première fois, initElement () stocke la version mise en cache de l'élément afin que la prochaine fois que le pilote ne recherche pas l'élément à la place, il se réfère au même cache et exécute l'action sur l'élément droit une façon.
@FindBy(id = 'unique') @CacheLookup private WebElement UniqueElement;
Voyons maintenant à travers un programme réel comment les actions sur l'élément Web mis en cache sont plus rapides que celles sur l'élément Web non mis en cache:
Améliorer encore le programme nseindia.com J'ai écrit une autre nouvelle méthode monitorPerformance () dans laquelle je crée un élément mis en cache pour la zone de recherche et un élément non mis en cache pour la même zone de recherche.
Ensuite, j'essaie d'obtenir le tagname de l'élément 3000 fois pour l'élément mis en cache et l'élément non mis en cache et j'essaie de mesurer le temps nécessaire pour terminer la tâche par l'élément mis en cache et non mis en cache.
J'ai considéré 3000 fois pour que nous puissions voir une différence visible dans les horaires des deux. Je m'attendrai à ce que l'élément mis en cache finisse d'obtenir le nom de variable 3000 fois en moins de temps par rapport à celui de l'élément non mis en cache.
Nous savons maintenant pourquoi l'élément mis en cache devrait fonctionner plus rapidement, c'est-à-dire que le pilote est chargé de ne pas rechercher l'élément après la première recherche mais de continuer directement à travailler dessus et ce n'est pas le cas avec l'élément non mis en cache où la recherche d'élément est effectuée. toutes les 3000 fois, puis l'action est effectuée dessus.
Voici le code de la méthode monitorPerformance ():
private void monitorPerformance() { //non cached element long NoCache_StartTime = System.currentTimeMillis(); for(int i = 0; i <3000; i ++) { Searchbox.getTagName(); } long NoCache_EndTime = System.currentTimeMillis(); long NoCache_TotalTime=(NoCache_EndTime-NoCache_StartTime)/1000; System.out.println('Response time without caching Searchbox ' + NoCache_TotalTime+ ' seconds'); //cached element long Cached_StartTime = System.currentTimeMillis(); for(int i = 0; i < 3000; i ++) { cachedSearchbox.getTagName(); } long Cached_EndTime = System.currentTimeMillis(); long Cached_TotalTime=(Cached_EndTime - Cached_StartTime)/1000; System.out.println('Response time by caching Searchbox ' + Cached_TotalTime+ ' seconds'); }
Lors de l'exécution, nous verrons le résultat ci-dessous dans la fenêtre de la console:
Selon le résultat, la tâche sur l'élément non mis en cache est terminée dans 82 secondes alors que le temps nécessaire pour terminer la tâche sur l'élément mis en cache était seulement 37 secondes. Il s'agit en effet d'une différence visible dans le temps de réponse de l'élément mis en cache et non mis en cache.
Q # 7) Quels sont les avantages et les inconvénients de l'annotation @CacheLookUp dans le concept Pagefactory?
Répondre:
Avantages @CacheLookUp et situations réalisables pour son utilisation:
@CacheLookUp est réalisable lorsque les éléments sont statiques ou ne changent pas du tout pendant le chargement de la page. Ces éléments ne modifient pas le temps d'exécution. Dans de tels cas, il est conseillé d'utiliser l'annotation pour améliorer la vitesse globale de l'exécution du test.
Inconvénients de l'annotation @CacheLookUp:
Le plus grand inconvénient d'avoir des éléments mis en cache avec l'annotation est la peur d'obtenir fréquemment des StaleElementReferenceExceptions.
Les éléments dynamiques sont rafraîchis assez souvent avec ceux qui sont susceptibles de changer rapidement sur quelques secondes ou minutes de l'intervalle de temps.
Voici quelques exemples de ces éléments dynamiques:
- Avoir un chronomètre sur la page Web qui met à jour le minuteur toutes les secondes.
- Un cadre qui met constamment à jour le bulletin météo.
- Une page rapportant les mises à jour en direct de Sensex.
Celles-ci ne sont pas du tout idéales ou réalisables pour l'utilisation de l'annotation @CacheLookUp. Si vous le faites, vous risquez d'obtenir l'exception de StaleElementReferenceExceptions.
Lors de la mise en cache de ces éléments, pendant l'exécution du test, le DOM des éléments est modifié, mais le pilote recherche la version du DOM qui était déjà stockée lors de la mise en cache. Cela rend l'élément obsolète à rechercher par le pilote qui n'existe plus sur la page Web. C'est pourquoi StaleElementReferenceException est levée.
Classes d'usine:
Pagefactory est un concept basé sur plusieurs classes et interfaces d'usine. Nous en apprendrons davantage sur quelques classes d'usine et interfaces ici dans cette section. Rares sont ceux que nous examinerons AjaxElementLocatorFactory , ElementLocatorFactory et DefaultElementFactory.
Nous sommes-nous déjà demandé si Pagefactory fournit un moyen d'incorporer l'attente implicite ou explicite de l'élément jusqu'à ce qu'une certaine condition soit satisfaite ( Exemple: Jusqu'à ce qu'un élément soit visible, activé, cliquable, etc.)? Si oui, voici une réponse appropriée.
AjaxElementLocatorFactory est l'un des contributeurs significatifs parmi toutes les classes d'usines. L'avantage d'AjaxElementLocatorFactory est que vous pouvez attribuer une valeur de délai d'expiration pour un élément Web à la classe de page Object.
Bien que Pagefactory ne propose pas de fonction d'attente explicite, il existe cependant une variante d'attente implicite à l'aide de la classe AjaxElementLocatorFactory . Cette classe peut être utilisée incorporée lorsque l'application utilise des composants et des éléments Ajax.
Voici comment vous l'implémentez dans le code. Dans le constructeur, lorsque nous utilisons la méthode initElements (), nous pouvons utiliser AjaxElementLocatorFactory pour fournir une attente implicite sur les éléments.
PageFactory.initElements(driver, this); can be replaced with PageFactory.initElements( new AjaxElementLocatorFactory(driver, 20), this);
La deuxième ligne ci-dessus du code implique que le pilote doit définir un délai d'expiration de 20 secondes pour tous les éléments de la page lorsque chacun de ses chargements et si l'un des éléments n'est pas trouvé après une attente de 20 secondes, 'NoSuchElementException' est levé pour cet élément manquant.
Vous pouvez également définir l'attente comme ci-dessous:
public pageFactoryClass(WebDriver driver) { ElementLocatorFactory locateMe = new AjaxElementLocatorFactory(driver, 30); PageFactory.initElements(locateMe, this); this.driver = driver; }
Le code ci-dessus fonctionne parfaitement car la classe AjaxElementLocatorFactory implémente l'interface ElementLocatorFactory.
Ici, l'interface parent (ElementLocatorFactory) fait référence à l'objet de la classe enfant (AjaxElementLocatorFactory). Par conséquent, le concept Java de «upcasting» ou de «polymorphisme d'exécution» est utilisé lors de l'attribution d'un délai d'attente à l'aide d'AjaxElementLocatorFactory.
En ce qui concerne son fonctionnement technique, AjaxElementLocatorFactory crée d'abord un AjaxElementLocator en utilisant un SlowLoadableComponent qui n'a peut-être pas fini de se charger lorsque load () revient. Après un appel à load (), la méthode isLoaded () doit continuer à échouer jusqu'à ce que le composant soit complètement chargé.
En d'autres termes, tous les éléments seront recherchés à chaque fois qu'un élément est accédé dans le code en appelant un appel à locator.findElement () de la classe AjaxElementLocator qui applique ensuite un délai d'attente jusqu'au chargement via la classe SlowLoadableComponent.
De plus, après l'attribution du délai d'expiration via AjaxElementLocatorFactory, les éléments avec l'annotation @CacheLookUp ne seront plus mis en cache car l'annotation sera ignorée.
Il existe également une variante de la façon tu peux appeler le initElements () méthode et comment vous ne devrait pas appeler le AjaxElementLocatorFactory pour attribuer un délai d'expiration à un élément.
# 1) Vous pouvez également spécifier un nom d'élément au lieu de l'objet pilote comme indiqué ci-dessous dans la méthode initElements ():
PageFactory.initElements( , this);
La méthode initElements () de la variante ci-dessus appelle en interne un appel à la classe DefaultElementFactory et le constructeur de DefaultElementFactory accepte l'objet d'interface SearchContext comme paramètre d'entrée. L'objet pilote Web et un élément Web appartiennent tous deux à l'interface SearchContext.
Dans ce cas, la méthode initElements () s'initialisera d'avance uniquement sur l'élément mentionné et tous les éléments de la page Web ne seront pas initialisés.
#deux) Cependant, voici une torsion intéressante à ce fait qui indique comment vous ne devriez pas appeler l'objet AjaxElementLocatorFactory d'une manière spécifique. Si j'utilise la variante ci-dessus de initElements () avec AjaxElementLocatorFactory, cela échouera.
Exemple: Le code ci-dessous, c'est-à-dire en passant le nom de l'élément au lieu de l'objet pilote à la définition AjaxElementLocatorFactory, ne fonctionnera pas car le constructeur de la classe AjaxElementLocatorFactory prend uniquement l'objet pilote Web comme paramètre d'entrée et, par conséquent, l'objet SearchContext avec l'élément Web ne fonctionnera pas pour lui.
PageFactory.initElements(new AjaxElementLocatorFactory(, 10), this);
Q # 8) L'utilisation de la pagefactory est-elle une option réalisable par rapport au modèle de conception d'objet de page normal?
Répondre: C'est la question la plus importante que se posent les gens et c'est pourquoi j'ai pensé y répondre à la fin du tutoriel. Nous connaissons désormais les «in and out» de Pagefactory à partir de ses concepts, des annotations utilisées, des fonctionnalités supplémentaires qu'il prend en charge, de la mise en œuvre via le code, des avantages et des inconvénients.
Pourtant, nous restons avec cette question essentielle que si pagefactory a tant de bonnes choses, pourquoi ne pas s'en tenir à son utilisation.
Pagefactory est livré avec le concept de CacheLookUp qui, nous l'avons vu, n'est pas faisable pour les éléments dynamiques comme les valeurs de l'élément qui sont souvent mis à jour. Alors, pagefactory sans CacheLookUp, est-ce une bonne option? Oui, si les xpaths sont statiques.
Cependant, le problème est que l'application de l'ère moderne est remplie d'éléments dynamiques lourds où nous savons que la conception d'objet de page sans pagefactory fonctionne finalement bien, mais le concept de pagefactory fonctionne-t-il aussi bien avec les xpaths dynamiques? Peut être pas. Voici un exemple rapide:
Sur la page Web nseindia.com, nous voyons un tableau comme indiqué ci-dessous.
Le xpath de la table est
'//*(@id='tab9Content')/table/tbody/tr(+count+)/td(1)'
Nous souhaitons récupérer les valeurs de chaque ligne pour la première colonne 'Acheter la quantité'. Pour ce faire, nous devrons incrémenter le compteur de lignes mais l'index de colonne restera 1. Il n'y a aucun moyen que nous puissions passer ce XPath dynamique dans l'annotation @FindBy car l'annotation accepte des valeurs statiques et aucune variable ne peut être transmise il.
Voici où la pagefactory échoue entièrement alors que le POM habituel fonctionne très bien avec elle. Vous pouvez facilement utiliser une boucle for pour incrémenter un index de ligne en utilisant de tels xpaths dynamiques dans la méthode driver.findElement ().
Conclusion
Le modèle d'objet de page est un concept ou un modèle de conception utilisé dans le cadre d'automatisation Selenium.
La convection de noms de méthodes est conviviale dans le modèle d'objet de page. Le code en POM est facile à comprendre, réutilisable et maintenable. Dans POM, s'il y a un changement dans l'élément Web, il suffit alors de faire les changements dans sa classe respective, plutôt que d'éditer toutes les classes.
Pagefactory, tout comme le POM habituel, est un merveilleux concept à appliquer. Cependant, nous devons savoir où le POM habituel est réalisable et où Pagefactory convient bien. Dans les applications statiques (où XPath et les éléments sont statiques), Pagefactory peut être généreusement implémenté avec des avantages supplémentaires de meilleures performances.
Alternativement, lorsque l'application implique à la fois des éléments dynamiques et statiques, vous pouvez avoir une implémentation mixte du pom avec Pagefactory et celle sans Pagefactory selon la faisabilité de chaque élément Web.
Auteur: Ce tutoriel a été écrit par Shobha D.Elle travaille en tant que chef de projet et possède plus de 9 ans d'expérience en manuel, automatisation (Selenium, IBM Rational Functional Tester, Java) et API Testing (SOAPUI et soyez assuré en Java) .
Maintenant à vous, pour une implémentation plus poussée de Pagefactory.
Bonne exploration !!!
=> Visitez ici pour apprendre le sélénium à partir de zéro.
lecture recommandée
- 30+ meilleurs didacticiels sur le sélénium: apprenez le sélénium avec de vrais exemples
- Script Selenium efficace et scénarios de dépannage - Tutoriel Selenium # 27
- Débogage de scripts Selenium avec des journaux (Tutoriel Log4j) - Tutoriel Selenium # 26
- Introduction au framework JUnit et à son utilisation dans Selenium Script - Tutoriel Selenium # 11
- 7 facteurs affectant l'estimation des tests du projet d'automatisation du sélénium - Tutoriel Selenium # 32
- Assertions dans Selenium à l'aide des cadres Junit et TestNG
- Comment utiliser le framework TestNG pour créer des scripts Selenium - Tutoriel TestNG Selenium # 12
- Apprenez à utiliser les annotations TestNG dans Selenium (avec des exemples)