Créer un environnement de test E2E avec Selenium (Java)

~~18/11/29 Si vous mettez à jour Selenide vers la dernière version (série ver5), cela ne fonctionnera pas. Il est préférable d'utiliser la dernière version, je vais donc le réparer plus tard. ~~ 18/12/03 J'ai essayé uniquement Chrome et mis à jour le code du programme. IE etc. reste tel qu'il est dans la description de capabilities.json.

introduction

AQ instantané: innocent: Afin d'améliorer progressivement la situation actuelle où les tests de régression prennent du temps, nous avons construit un environnement pour automatiser les tests système qui font la même chose à plusieurs reprises. J'ai ce dossier.

Je n'ai pas enregistré comment exécuter le test car il vaut mieux se référer au Tutoriel Pitalium.

Logiciel utilisé

Il s'agit du logiciel utilisé pour la vérification. Tout était super. Vous pouvez tester avec Selenium Grid (configuration Hub, Node) en utilisant Pitalium. Je construis une version de vérification sur Windows.

doux version Utilisation
java 1.8.0_191
Pitalium 1.2.4 Utilisé comme base
Selenide 5.0.1 Utilisé uniquement avec PageObject
selenium-server-standalone.jar 3.141.59
chromedriver.exe 2.44

Environnement

Poursuivez avec Pitalium Tutorial pour créer un environnement d'exécution de test.

18/04/23 ClassNotFound peut se produire dans CI (Jenkins), donc je l'ai changé en Maven. La portée n'est pas de test car nous l'essayons dans un projet de test.

Dossier Maven

<détails>

Fichier Maven (décompression) </ summary>

pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>Autotest</groupId>
  <artifactId>Autotest</artifactId>
  <version>0.0.1</version>
  <build>
    <sourceDirectory>src</sourceDirectory>
    <testSourceDirectory>src</testSourceDirectory>
    <resources>
      <resource>
        <directory>resource</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>resource</directory>
      </testResource>
    </testResources>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.3</version>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.12.4</version>
      </plugin>
    </plugins>
  </build>
  <dependencies>
  	<dependency>
  		<groupId>com.htmlhifive</groupId>
  		<artifactId>pitalium</artifactId>
  		<version>1.2.4</version>
  		<exclusions>
  			<exclusion>
  				<groupId>org.slf4j</groupId>
  				<artifactId>slf4j-api</artifactId>
  			</exclusion>
  		</exclusions>
  	</dependency>
  	<dependency>
  		<groupId>com.codeborne</groupId>
  		<artifactId>selenide</artifactId>
  		<version>5.0.1</version>
  		<exclusions>
  			<exclusion>
  				<groupId>org.apache.httpcomponents</groupId>
  				<artifactId>httpclient</artifactId>
  			</exclusion>
  			<exclusion>
  				<groupId>org.slf4j</groupId>
  				<artifactId>slf4j-api</artifactId>
  			</exclusion>
  		</exclusions>
  	</dependency>
  	<dependency>
  		<groupId>org.seleniumhq.selenium</groupId>
  		<artifactId>selenium-api</artifactId>
  		<version>3.141.59</version>
  	</dependency>
  	<dependency>
  		<groupId>org.seleniumhq.selenium</groupId>
  		<artifactId>selenium-remote-driver</artifactId>
  		<version>3.141.59</version>
  	</dependency>
  	<dependency>
  		<groupId>org.seleniumhq.selenium</groupId>
  		<artifactId>selenium-support</artifactId>
  		<version>3.141.59</version>
  	</dependency>
  	<dependency>
  		<groupId>com.google.guava</groupId>
  		<artifactId>guava</artifactId>
  		<version>27.0.1-jre</version>
  	</dependency>
  	<dependency>
  		<groupId>org.slf4j</groupId>
  		<artifactId>slf4j-log4j12</artifactId>
  		<version>1.8.0-beta2</version>
  	</dependency>
  	<dependency>
  		<groupId>org.apache.httpcomponents</groupId>
  		<artifactId>httpclient</artifactId>
  		<version>4.5.6</version>
  	</dependency>
  </dependencies>
  <properties>
    <java.version>1.8</java.version>
    <file.encoding>UTF-8</file.encoding>
  	<project.build.sourceEncoding>${file.encoding}</project.build.sourceEncoding>
  	<project.reporting.outputEncoding>${file.encoding}</project.reporting.outputEncoding>
    <maven.compiler.encoding>${file.encoding}</maven.compiler.encoding>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
  </properties>
</project>

Mon environnement ressemble à ceci: En raison du problème décrit plus loin, IE a finalement été lancé séparément dans un autre nœud.

Commande de démarrage du concentrateur

<détails> <résumé> Commande de démarrage du concentrateur (développer) </ résumé>

java -jar selenium-server-standalone-3.141.59.jar -role hub
Fichier de configuration du nœud

<détails>

Fichier de configuration du nœud (décompression) </ summary>

NodeConfigBrowser.json


{
 "capabilities": [
    {
     "platform": "WINDOWS",
     "browserName": "firefox",
     "maxInstances": 2,
     "seleniumProtocol": "WebDriver"
    },
    {
     "platform": "WINDOWS",
     "browserName": "chrome",
     "maxInstances": 3,
     "seleniumProtocol": "WebDriver"
    },
    {
     "platform": "WINDOWS",
     "browserName": "internet explorer",
     "maxInstances": 1,
     "seleniumProtocol": "WebDriver"
    }
  ],
 "hub": "http://XXX.XXX.XXX.XXX:4444/grid/register",
 "register": true
}
Commande de démarrage de nœud

<détails>

Commande de démarrage du nœud (développer) </ summary>

java -Dwebdriver.ie.driver=IEDriverServer.exe -Dwebdriver.chrome.driver=chromedriver.exe -Dwebdriver.gecko.driver=geckodriver.exe -jar selenium-server-standalone-3.141.59.jar -role node -nodeConfig NodeConfigBrowser.json

Structure du programme

La structure des répertoires peut changer, mais pour le moment, je l'ai faite avec la structure suivante.

aWS050227.JPG

  • paquet de page

Attiré par le son du motif PageObject, j'ai décidé de créer un écran avec un objet pour le moment. J'utilise Selenide ici.

~~ Puisque la génération de WebDriver est laissée à Pitalium, j'ai créé une classe parent et passé WebDriver à Selenide dans le constructeur. ~~ 18/12/03 La dernière version de Selenide (série ver5) avait un problème ici. Modifié pour spécifier le pilote à utiliser par Selenide une seule fois dans la classe parent du scénario de test

Classe de page parent

<détails>

Classe de la page parent (extension) </ summary>

PageBase.java


package page;

import com.htmlhifive.pitalium.core.config.PtlTestConfig;

/**
 *Classe parente de page pour le traitement courant tel que les en-têtes et pieds de page
 */
public abstract class PageBase {

    /**URL de base commençant par http ou https*/
    protected final String _BASE_URL = PtlTestConfig.getInstance().getTestAppConfig().getBaseUrl();

    /*********************************
     *Opération commune
     *********************************/

}
Classe de page enfant
Classe de page enfant (extension)

La raison pour laquelle le nom de classe, etc. est en japonais sera décrite plus loin.

S'identifier.java


package page;

import static com.codeborne.selenide.Selenide.*;

public class __L'écran de connexion étend PageBase{

    public static final String _URL = "/login";

    /*********************************
     *sélecteur
     *********************************/

    //identifiant de compte
    private static final String _ACCOUNT_TXT_CSS = "#accountID";
    //mot de passe
    private static final String _PASS_TXT_CSS = "#password";
    //Bouton de connexion
    private static final String _LOGIN_BTN_CSS = "#login";

    /*********************************
     *opération
     *********************************/

    public __Écran de connexion__Entrez votre identifiant de compte(String s) {
        $(_ACCOUNT_TXT_CSS).setValue(s);
        return this;
    }

    public __Écran de connexion__Entrer le mot de passe(String s) {
        $(_PASS_TXT_CSS).setValue(s);
        return this;
    }

    public __Écran de connexion__Cliquez sur le bouton de connexion() {
        $(_LOGIN_BTN_CSS).click();
        return this;
    }

}
  • paquet de test

Créé en héritant de la classe Pitalium. Nous effectuons des opérations de test et des comparaisons d'images.

Encore une fois, j'ai décidé de mettre dans une classe de parents comme base pour le moment.

Classe de test parent

<détails>

Classe de test parent (développement) </ summary>

TestBase.java


package test;

import java.util.Locale;

import org.junit.Before;
import org.junit.Rule;

import com.codeborne.selenide.Configuration;
import com.codeborne.selenide.WebDriverRunner;
import com.codeborne.selenide.commands.Commands;
import com.codeborne.selenide.junit.TextReport;
import com.google.common.base.Strings;
import com.htmlhifive.pitalium.core.PtlTestBase;
import com.htmlhifive.pitalium.core.model.ScreenshotArgument;

import custom.SetValueCustomize;

public abstract class TestBase extends PtlTestBase {

    /**Rapport de performance Selenide*/
    @Rule
    public TextReport report = new TextReport();

    private int _ssCount = 1;

    @Override
    @Before
    public void setUp() {
        super.setUp();

        //Remplacé par la commande qui a ajouté le traitement pour IE
        Commands.getInstance().add("setValue", new SetValueCustomize(Strings.nullToEmpty(capabilities.getBrowserName()).toLowerCase(Locale.ENGLISH)));

        //Définir le délai d'expiration de la recherche d'élément à 10 secondes et définir le pilote Selenide
        Configuration.timeout = 10000;
        WebDriverRunner.setWebDriver(driver);

        //La valeur par défaut est aucune sortie de rapport de performances
        report.onSucceededTest(false);
        report.onFailedTest(false);

        //Prétraitement de l'exécution des tests
        init();
    }

    /**
     *Prétraitement de l'exécution des tests
     */
    protected void init() {};

    /**
     *Activer les rapports de performances Selenide
     */
    protected void enablePerfReport() {
        report.onSucceededTest(true);
        report.onFailedTest(true);
    }

    /**
     *Déterminez s'il s'agit d'un navigateur Chrome
     * @return true:Chrome
     */
    protected boolean isChrome(){
        return "chrome".equals(Strings.nullToEmpty(capabilities.getBrowserName()).toLowerCase(Locale.ENGLISH)) ? true : false;
    }

    /**
     *Déterminez s'il s'agit d'un navigateur Edge
     * @return Edge
     */
    protected boolean isEdge(){
        return "MicrosoftEdge".equals(Strings.nullToEmpty(capabilities.getBrowserName()).toLowerCase(Locale.ENGLISH)) ? true : false;
    }

    /**
     *Juger s'il s'agit d'un navigateur IE
     * @return IE
     */
    protected boolean isIE(){
        return "internet explorer".equals(Strings.nullToEmpty(capabilities.getBrowserName()).toLowerCase(Locale.ENGLISH)) ? true : false;
    }

    /**
     *Prendre une capture d'écran
     */
    protected void screenShotAndVerifyView() {
        screenShotAndVerifyView("image");
    }

    /**
     *Prendre une capture d'écran
     * @param Nom de la capture d'écran
     */
    protected void screenShotAndVerifyView(String screenName) {
        ScreenshotArgument arg = ScreenshotArgument.builder(screenName + _ssCount).addNewTarget().build();
        assertionView.verifyView(arg);
        _ssCount++;
    }

}
Classe de test enfant

<détails>

Classe de test enfant (développement) </ summary>

LoginTest.java


package test;

import org.junit.Test;

import page.__Écran de connexion;

public class LoginTest extends TestBase {
    @Test
    public void loginOK() throws Exception {
        driver.get(__Écran de connexion._url);
        __Page d'écran de connexion= new __Écran de connexion();

        page.__Entrez votre identifiant de compte("user")
                .__Entrer le mot de passe("password")
                .__Cliquez sur le bouton de connexion();

        assertionView.assertView("loginOK");
    }
}

Choses à surveiller

Étant donné que certaines personnes de l'équipe de test hésitent à dire simplement des caractères horizontaux, nous avons décidé d'écrire toutes les classes et méthodes liées aux opérations sur écran en japonais.

En outre, la méthode de fonctionnement de l'écran est également conçue de manière à ce que les candidats puissent être facilement réduits avec deux barres inférieures.

Je pense que le seuil est élevé car il n'y a personne qui ait une expérience de codage en qualité, donc j'aimerais continuer avec la classe de page en développement.

classe de page: écriture de code de développement classe de test: équipe de qualité et de test codée

difficulté

Je ne pense pas avoir eu beaucoup de problèmes avec l'opération que je veux faire: étreindre: Cependant, IE et Teme ne sont pas bons.

J'ai des difficultés à saisir du texte dans IE

Je ne connais pas la raison, mais le phénomène selon lequel l'entrée échoue uniquement dans IE se produit. Dans IE, il y a beaucoup d'informations comme il vaut mieux mettre les contrôles à l'avance et les clics, donc je n'ai pas compris donc j'ai décidé de tout faire: rolling_eyes: Correspond au processus de saisie avec Selenide par accrochage (pour être exact, il peut être remplacé).

Classe de commande personnalisée
Classe de commande personnalisée (extension)

SetValueCustomize.java


package common;

import java.io.IOException;

import org.openqa.selenium.Keys;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;

import com.codeborne.selenide.Configuration;
import com.codeborne.selenide.SelenideElement;
import com.codeborne.selenide.commands.Commands;
import com.codeborne.selenide.commands.SetValue;
import com.codeborne.selenide.impl.WebElementSource;

/**
 *Classe de remplacement SetValue
 *La différence est la correspondance individuelle de IE
 */
public class SetValueCustomize extends SetValue {

    private boolean _ieFlg;

    public SetValueCustomize(String _browserName) {
        _ieFlg = "internet explorer".equals(_browserName) ? true : false;
    }

    @Override
    public WebElement execute(SelenideElement proxy, WebElementSource locator, Object[] args) {
        WebElement element = locator.findAndAssertElementIsVisible();

        if (Configuration.versatileSetValue
                && "select".equalsIgnoreCase(element.getTagName())) {
            return super.execute(proxy, locator, args);
        }
        if (Configuration.versatileSetValue
                && "input".equalsIgnoreCase(element.getTagName()) && "radio".equals(element.getAttribute("type"))) {
            return super.execute(proxy, locator, args);
        }

        if (_ieFlg) {
            element.sendKeys(Keys.CONTROL);
            try {
                Commands.getInstance().execute(proxy, locator, "click", null);
            } catch (IOException e) {
                throw new NoSuchElementException("IE Click error in SetValueCustomize", e);
            }
        }

        return super.execute(proxy, locator, args);
    }
}

Remplacez à l'avance la commande créée par la classe de test parent.

TestBase.java



public abstract class TestBase extends PtlTestBase {
    @Override
    @Before
    public void setUp() {
        super.setUp();
        //Remplacé par la commande qui a ajouté le traitement pour IE
        Commands.getInstance().add("setValue", new SetValueCustomize(Strings.nullToEmpty(capabilities.getBrowserName()).toLowerCase(Locale.ENGLISH)));
    }
}

Lorsque la méthode setValue est appelée dans diverses classes de page, la classe associée au nom de méthode spécifié est acquise à partir de la carte des commandes à l'intérieur de Selenide et execute est appelée.

S'identifier.java



la connexion de classe publique étend PageBase{

connexion publique__Entrez votre identifiant de connexion(String id) {
        $("#account").setValue(id);
        return this;
    }
}

Dans IE, le menu Hover s'affiche pendant seulement 0,1 seconde (expérience) et les éléments enfants ne peuvent pas être sélectionnés.

Laissez la souris telle quelle! Il semblait que cela ne serait pas résolu même si je criais, alors je l'ai traité en spécifiant les capacités avec se: ieOptions.

fonctionnalités ieOptions version supplémentaire
capabilities.json

capabilities.json


[
 {
  "browserName": "internet explorer",
  "se:ieOptions" : {
    "enablePersistentHover" : true,
    "requireWindowFocus" : true
  }
 }
]

En raison de ces choses, il a été décidé arbitrairement de préparer un Node (terminal) qui est dédié à IE et que IE ne démarre qu'un seul processus et ne permet pas le fonctionnement ou à distance des autres: innocent:

NodeConfig pour terminal IE uniquement

<détails>

NodeConfig pour le terminal IE uniquement </ summary>

NodeConfigBrowser.json


{
 "capabilities": [
    {
     "platform": "WINDOWS",
     "browserName": "internet explorer",
     "maxInstances": 1,
     "seleniumProtocol": "WebDriver"
    }
  ],
 "hub": "http://XXXXX:4444/grid/register",
 "register": true
}

Dans IE et Firefox, une boîte de dialogue etc. s'affiche lors du téléchargement et l'opération ne fonctionne pas (Non résolu * Cela peut être résolu en utilisant WinAppDriver. *)

Firefox a essayé de définir des fonctionnalités avec moz: firefoxOptions --prefs, mais cela n'a pas fonctionné, j'ai donc décidé de ne pas télécharger de test autre que Chrome: innocent:

fonctionnalités firefoxOptions version supplémentaire (inutile)
(sans signification) capabilities.json

capabilities.json


[
 {
  "browserName": "firefox",
  "moz:firefoxOptions": {
    "prefs": {
        "browser.download.folderList": 0,
        "browser.download.useDownloadDir": true,
        "browser.helperApps.neverAsk.saveToDisk": "text/*,application/*",
        "browser.helperApps.alwaysAsk.force": false,
        "browser.download.manager.closeWhenDone": true,
        "pdfjs.enabledCache.state": false
    }
  }
 }
]

Recommended Posts