Comment créer une classe de test de base pour les tests Selenium et initialiser via JUnit RuleChain

Avec cet article, nous continuons une série de publications sur la façon dont nous avons automatisé le processus de test manuel (ci-après dénommé auto-tests) d'un grand système d'information (ci-après dénommé Systèmes) dans l'un des principaux projets LANIT et ce qui en est ressorti.

Comment organiser efficacement une hiérarchie de classes? Comment distribuer des packages sur l'arborescence du projet? Comment vous assurer d'oublier les conflits de fusion avec une équipe de 10 personnes? Ces problèmes sont toujours au début d'un nouveau développement et ils n'ont jamais assez de temps.

Source

Dans cet article, nous décrivons la structure des classes et l'organisation du code, ce qui nous a permis de développer avec peu d'effort plus d'un millier de tests d'interface utilisateur de bout en bout basés sur Junit et Selenium pour un grand système d'importance fédérale. De plus, nous le soutenons avec succès et affinons constamment les scénarios existants.

Vous trouverez ici une description pratique de la structure de la hiérarchie des classes de base des autotests, la répartition du projet selon le modèle fonctionnel java-packages et des exemples de modèles de classes réelles.

L'article sera utile à tous les développeurs qui développent des auto-tests basés sur Selenium.

Cet article fait partie d'une publication générale dans laquelle nous avons décrit comment une petite équipe a construit le processus d'automatisation des tests d'interface utilisateur et développé un cadre basé sur Junit et Selenium pour cela.

Parties précédentes:


Implémentation de la classe de base pour tous les tests et JUnit RuleChain


Le concept de développement d'autotests, comme indiqué dans un article précédent ( Partie 2. Technique. Architecture et pile technique. Détails d'implémentation et surprises techniques ), est basé sur l'idée d'un cadre dans lequel un ensemble de fonctions système est fourni pour tous les autotests - ils sont parfaitement intégrés et permettent aux développeurs les autotests se concentrent sur des questions spécifiques de l'implémentation commerciale des classes de test.

Le cadre comprend les blocs fonctionnels suivants:

  • Règles - initialisation et finalisation des composants de l'infrastructure de test comme initialisation de WebDriver et réception d'un test vidéo. Décrit plus en détail ci-dessous;
  • WebDriverHandlers - fonctions d'assistance pour travailler avec un pilote Web comme exécuter Java Script ou accéder aux journaux du navigateur. Implémenté comme un ensemble de méthodes statiques sans état;
  • WebElements est une bibliothèque d'éléments Web typiques ou de leurs groupes, qui contient la fonctionnalité inter-fonctions requise et le comportement typique. Dans notre cas, cette fonctionnalité comprend une vérification éventuelle de la fin des opérations asynchrones du côté du navigateur Web. Implémenté en tant qu'extensions d'éléments Web à partir des bibliothèques Selenium et Selenide.

Initialisation de l'environnement de test. Les règles


La classe clé pour toutes les classes de test est BaseTest, dont toutes les classes de test sont héritées. La classe BaseTest définit le «runner» Junit des tests et la RuleChain utilisée, comme indiqué ci-dessous. L'accès des classes de test appliquées aux fonctions fournies par les classes de règles est fourni via les méthodes statiques des classes de règles.

L'exemple de code BaseTest est présenté dans la zone suivante.

@RunWith(FilterTestRunner.class) public class BaseTest { private TemporaryFolder downloadDirRule                                                                  = new TemporaryFolder(getSomething().getWorkingDir());      @Rule     public RuleChain rules = RuleChain             .outerRule(new Timeout(TimeoutEnum.GLOBAL_TEST_TIMEOUT.value(),                                                                       TimeUnit.SECONDS))             .around(new TestLogger())             .around(new StandStateChecker())             .around(new WaitForAngularCreator())             .around(downloadDirRule)             .around(new DownloaderCreator(downloadDirRule))             .around(new EnvironmentSaver())             .around(new SessionVideoHandler())             .around(new DriverCreator(downloadDirRule))             .around(new BrowserLogCatcher(downloadDirRule))             .around(new ScreenShooter())             .around(new AttachmentFileSaver())             .around(new FailClassifier())             .around(new PendingRequestsCatcher());     //            final protected SomeObject getSomething() {         return Something.getData();    }    … } 

FilterTestRunner.class - une extension de BlockJUnit4ClassRunner, fournit un filtrage de la composition des tests exécutables basés sur des expressions régulières par la valeur de l'annotation spéciale de filtre (valeur = "some_string_and_tag"). L'implémentation est donnée ci-dessous.

org.junit.rules.Timeout - utilisé pour limiter la poursuite maximale des tests. Il doit être installé en premier, car il démarre le test dans une nouvelle branche.

TestLogger est une classe qui permet au test de consigner les événements au format json pour une utilisation dans l'analyse ELK. Enrichit les événements avec les données de test de org.junit.runner.Description. De plus, il génère automatiquement des événements pour ELK au format json pour démarrer / terminer le test avec sa durée et son résultat.

StandStateChecker est une classe qui vérifie la disponibilité de l'interface Web du stand cible AVANT d'initialiser le pilote Web. Permet de vérifier rapidement que le support est disponible en principe.

WaitForAngularCreator - une classe qui initialise le gestionnaire de pilote Web pour contrôler la fin des opérations angulaires asynchrones. Il est utilisé pour personnaliser les tests "spéciaux" avec de longs appels synchrones.

org.junit.rules.TemporaryFolder - utilisé pour définir un dossier temporaire unique pour le stockage des fichiers pour les opérations de téléchargement et de téléchargement de fichiers via un navigateur Web.

DownloaderCreator est une classe qui prend en charge les opérations de téléchargement vers un répertoire temporaire de fichiers téléchargés par le navigateur et enregistrés via la fonction vidéo Selenoid.

EnvironmentSaver - une classe qui ajoute des informations générales sur l' environnement de test au rapport Allure.  

SessionVideoHandler - une classe qui télécharge un fichier de test vidéo, le cas échéant, et applique Allure au rapport.

DriverCreator est une classe qui initialise WebDriver (la classe la plus importante pour les tests) en fonction des paramètres définis - local, solénoïde ou ggr-selenoid. De plus, la classe exécute l'ensemble de scripts Java requis pour nos tests. Toutes les règles qui accèdent au pilote Web doivent être initialisées après cette classe.

BrowserLogCatcher - une classe qui lit les messages graves du journal du navigateur, les enregistre dans ELK (TestLogger) et l'applique au rapport Allure.

ScreenShooter - une classe qui, pour les tests infructueux, prend une capture d'écran de l'écran du navigateur et l'applique au rapport en tant que WebDriverRunner.getWebDriver (). GetScreenshotAs (OutputType.BYTES)

AttachmentFileSaver - une classe qui vous permet de joindre au rapport Allure un ensemble de fichiers arbitraires requis par la logique métier des tests. Utilisé pour joindre des fichiers téléchargés ou téléchargés sur le système.

FailClassifier est une classe spéciale qui, en cas de panne de test, tente de déterminer si cette panne a été causée par des problèmes d'infrastructure. Vérifie la présence à l'écran (après un crash) de fenêtres modales spéciales du type «Erreur système n ° XXXXXXXXXX s'est produite», ainsi que des messages système de type 404 et similaires. Vous permet de diviser les tests tombés en plantages d'entreprise (selon le scénario) ou problèmes système. Fonctionne via l'extension org.junit.rules.TestWatcher. # Échec de la méthode.

PendingRequestsCatcher est une autre classe spéciale qui tente de classer davantage si l'accident a été causé par des services de repos incomplets, bloqués ou très longs entre l'angulaire et l'interface Web. En plus des tests fonctionnels, il permet d'identifier les services de repos problématiques et gelés sous fortes charges, ainsi que la stabilité globale de la version. Pour ce faire, la classe enregistre dans ELK tous les événements avec des demandes de repos figées qu'elle reçoit en lançant des js spéciaux dans le navigateur via un pilote Web ouvert.

Modèle d'implémentation de classe de test


 package autotest.test.<sub-system>; @Feature("     TMS") @Story("    TMS") @Owner("       ") @TmsLink("    .   ") public class <   >_Test extends BaseTest { /** *           **/    Login orgTest; /**         **/    Login loginStep1;    ...    Login loginStepN;    /** *   -      -   * ...         **/      /** *    *              *    Utils.allure.message("     -", business_object) *     null,             . *             preconditions  actions    *  Utils.allure.message("      ", documentNumber) **/ @Step("  ") private void init(Login login) {    some_business_object = //         login        Utils.allure.message("     -", some_business_object)                           // ...             /**     */        loginStep1 = LoginFactory.get(_Some_Login_);    ...    loginStepN = LoginFactory.get(_Some_Login_); }    /** *       **/    @Test    @Filter("       JUnit")    @DisplayName("    TMS")    public void <   >_<>_<__>_Test() {  //            orgTest = LoginFactory.get(_Some_Login_);                //               init(orgTest);           //    -.                preconditions();               //             actions(orgTest); }    /** *        **/ @Step(" ") protected void preconditions() {    loginStep1.login();    new SomeAction().apply(someTestObject1, ..., someTestObjectN);        Utils.allure.message("   -      -", someTestObjectN)        ...    }    /** *        */ @Step(" ") protected void actions(Login testLogin) {    testLogin.reLogin();               //                new SomeAction().apply(someTestObject1, ..., someTestObjectN); } } 

Modèle d'implémentation de classe de script de test


 package autotest.business.actions.some_subsystem; public class SomeAction {            //   PageClassA pageA = new PageClassA(); PageClassB pageB = new PageClassB();    @Step("     TMS")    @Description("     TMS")    public void apply(someTestObject1, ..., someTestObjectN) {    //   TMS        step_1(...);        step_2(...);        ...        step_N(...);    }    @Step("  1    TMS")    private void step_1(...) {       pageA.createSomething(someTestObject1);// just as an example create }    @Step("  2    TMS")    private void step_2(...) {   pageA.checkSomething(someTestObject1);// just as an example }                       ... } 

Implémentation de la classe de filtrage de test FilterTestRunner


Voici une implémentation de l'extension BlockJUnit4ClassRunner pour filtrer les tests basés sur des ensembles de balises arbitraires.

 /** * Custom runner for JUnit4 tests. * Provide capability to do additional filtering executed test methods * accordingly information that could be provided by {@link FrameworkMethod} */ public class FilterTestRunner extends BlockJUnit4ClassRunner { private static final Logger LOGGER = Logger.getLogger(FilterTestRunner.class.getName()); public FilterTestRunner(Class<?> klass) throws InitializationError {    super(klass); } /** * This method should be used if you want to hide filtered tests completely from output **/ @Override protected List<FrameworkMethod> getChildren() {    //  ,        @Filter       TestFilter filter = TestFilterFactory.get();    List<FrameworkMethod> allMethods = super.getChildren();    List<FrameworkMethod> filteredMethod = new ArrayList<>();    for (FrameworkMethod method: allMethods) {        if (filter.test(method)) {            LOGGER.config("method [" + method.getName() +"] passed by filter [" + filter.toString() + "]" );            filteredMethod.add(method);        } else {            LOGGER.config("method [" + method.getName() +"] blocked by filter [" + filter.toString() + "]" );        }    }    return Collections.unmodifiableList(filteredMethod); } /** * This method should be used if you want to skip filtered tests but no hide them @Override protected boolean isIgnored(FrameworkMethod method) {    …    if (filter.test(method)) {        return super.isIgnored(method);    } else {     return true;  }} */ } 

Dans la partie suivante, je parlerai de la façon dont nous avons implémenté le processus de téléchargement d'un fichier du conteneur avec le navigateur vers le framework de test, et résolu le problème de trouver le nom du fichier téléchargé par le navigateur.

Soit dit en passant, nous serons heureux de reconstituer notre équipe. Les postes vacants sont ici .

Source: https://habr.com/ru/post/fr480910/


All Articles