IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Robotframework

Automatisation de tests

Lors de tout développement se pose à un moment donné la question des tests.

En effet, afin de garantir un minimum de qualité aux utilisateurs, il faut effectuer des tests unitaires, d'intégration et fonctionnels. Et là se pose une alternative : manuel ou auto.

Si pour un tout petit logiciel cela n'a pas d'importance, il en est tout autrement lorsque le logiciel grossit. L'automatisation prend alors toute son importance. Pouvoir passer toute une batterie de tests, rapidement et simplement lire le compte-rendu s'avère un gain de temps non négligeable.

Qui plus est, cela peut également permettre de lancer les tests plus souvent afin de déceler plus rapidement une erreur de programmation.

Composants de l'intégration continue, les tests automatiques sont l'une des clés de la qualité d'un produit.

12 commentaires Donner une note à l´article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Je vous propose ici de passer en revue les bases de RobotFrameWorkhttp://robotframework.org/ (RFW).

Outil puissant permettant de créer simplement des tests automatisés, RFW sait s'adapter aux utilisateurs et propose de faire le choix de programmer en mode verbeux, ou directement en Python pour les développeurs.

De plus, capable de s'interfacer avec des bibliothèques tierces, ses capacités sont extrêmement étendues. Parmi les solutions répandues, figurent ainsi entre autres le test de site web, ou encore SSH. Quant aux bibliothèques intégrées, elles vous fourniront l'essentiel pour la plupart des tests.

Le sujet étant ainsi très vaste, nous verrons ici l'essentiel (mode statique) afin que vous puissiez appréhender au mieux les bases de cet outil. Pour les spécificités, je vous renvoie à la fin de ce tutoriel où vous trouverez les différents liens qui vous seront utiles.

Veuillez noter que dans la mesure où nombre de notions se recoupent entre elles, vous serez probablement amené à relire ce tutoriel plusieurs fois afin de bien assimiler les finesses de RFW.

II. Présentation

II-A. Historique rapide

Créée en 2005, suite à un sujet de thèse de Pekka Klärck, la première version fut éditée par Nokia. Ce framework est devenu Open Source à l'occasion de la V2, en 2008.

Il est basé sur le langage Python, et distribué sous licence Apache.

II-B. Les principales bibliothèques standard

II-B-1. Built-in

Historiquement la première et seule bibliothèque de RFW, elle accueille un certain nombre de Keywords génériques divers et variés. Si dans les autres bibliothèques vous pensez qu'un Keyword est manquant, consultez cette bibliothèque, car il se peut que pour des raisons de rétrocompatibilité, le keyword n'ait pas été déplacé.

II-B-2. Collections

Cette bibliothèque vise à mettre à disposition des keywords pour la création et la manipulation de listes et de dictionnaires Python. À noter qu'historiquement, c'était la bibliothèque Built-in qui accueillait ce rôle. Aussi, dans un souci de rétrocompatibilité, certains Keywords sont toujours dans la bibliothèque Built-In.

II-B-3. Process

Cette bibliothèque met à votre disposition des outils afin d'effectuer du multiprocess basique.

II-B-4. String

Cette bibliothèque permet de manipuler les chaînes de caractères et d'effectuer des tests sur ces dernières.

II-B-5. Screenshot

Cette bibliothèque n'a qu'un seul but : fournir les keywords nécessaires pour effectuer des screenshots.

II-B-6. Operating System

Cette bibliothèque vous permettra d'interagir avec l'OS. Par exemple, la création de dossiers/fichiers, tester leurs existences…

II-B-7. Telnet

Il s'agit d'une bibliothèque qui vous permettra d'établir des connexions Telnet vers vos serveurs.

II-B-8. Dialogs

Elle met à votre disposition des moyens d'interagir avec l'utilisateur.

II-C. Les principaux add-ons

Nous n'allons pas aborder ici l'utilisation de ces extensions, car cela sort du cadre de l'utilisation basique de RFW.

Il peut cependant être utile de savoir qu'elles existent. Pour leur utilisation, je vous renvoie vers leurs sites respectifs qui expliquent comment les intégrer à RFW. À noter que cette liste n'est pas exhaustive.

Bien entendu, la plupart de ces bibliothèques tierces, exception faite de spécifiques telles Selenium ou AutoIT, sont inutiles si vous programmez 100 % du code en Python.

Les bibliothèques tierces présentées ici ne sont utiles que dans le cas où vous programmez un minimum en scripts RobotFrameWork.

II-C-1. Selenium

Selenium est une bibliothèque RFW tierce permettant de manipuler les sites web. Il existe SeleniumLibrary et Selenium2Library. C'est cette dernière qu'il faut désormais utiliser. Elle utilise un webdriver afin de piloter les différents navigateurs.

La bibliothèque Selenium étant développée sous Firefox, c'est sous ce navigateur que la compatibilité est maximale.

II-C-2. AutoIT

Cette bibliothèque tierce vous permettra de manipuler des applications MS Windows sous réserve qu'elles n'utilisent pas des technologies trop récentes. À titre d'exemple, MS Office n'est pas manipulable, mais un installeur Inno Setup l'est.

À titre d'information, il existe une bibliothèque s'appelant Pywinauto, 100 % Python, permettant de faire la même chose.

II-C-3. SSHLibrary

Cette bibliothèque tierce vous permettra d'effectuer des tâches via SSH, et ainsi de manipuler une machine distante. Très pratique en environnement Unix.

II-C-4. DataBase Library Python

DataBase Library Python est une bibliothèque tierce RFW qui vous permettra de manipuler un certain nombre de BDD afin d'y effectuer diverses opérations.

II-C-5. FTP Library

Cette bibliothèque tierce vous permettra d'effectuer des tâches FTP en simulant un client FTP.

II-C-6. DiffLibrary

Cette bibliothèque tierce vous permettra de comparer deux fichiers texte simplement.

II-D. Les éditeurs

Afin d'écrire vos tests, il peut être intéressant de disposer d'une coloration syntaxique. Pour cela, vous disposez de deux solutions principales : RIDE ou un plugin.

Bien sûr, rien ne vous empêche également d'utiliser un simple éditeur de texte.

II-D-1. RIDE

Image non disponible

Il s'agit de l'IDE officiel de RFW. Assez complet, même si d'aspect simpliste, il nécessite l'installation de wxwidget.

Il vous permettra de lancer directement vos tests sans passer par la ligne de commande.

Il a été constaté que certains tests spécifiques tombaient en erreur uniquement lorsque lancés depuis l'IDE. Si l'échec de vos tests vous paraît anormal, n'hésitez alors pas à les relancer en ligne de commande.

II-D-2. Plugins

C'est la seconde solution, et la plus répandue. Nombreux sont les IDE génériques à disposer de plugin RFW. Selon la qualité de ces plugins, vous pourrez également lancer les tests depuis votre IDE ou encore récupérer les logs de résultats.

Je vous invite également à regarder du côté de « pygments » qui vous permettra de disposer d'une préconfiguration RFW pour la coloration syntaxique de votre code.

II-E. Les interactions possibles avec les outils de build

Comme explicité lors de l'introduction, RFW est une brique essentielle pour l'automatisation complète d'une chaîne de build. Parmi les outils classiques, nous pouvons citer Ant, Maven et Jenkins (fork de Hudson).

Il faut savoir que RFW s'intègre parfaitement à ce genre d'outil, et très simplement. En général les sites de ces outils disposent d'explications et/ou de plugins dédiés.

III. Installation

Comme d'habitude avec Python, le plus simple est l'installation via Pypi. Les modules s'appellent « robotframework » et « robotframework-ride ».

 
Sélectionnez
pip install robotframework
pip install robotframework-ride

RIDE nécessite wxPython (wxgtk). Il se lance ensuite avec la commande « ride.py »

IV. Utilisation

IV-A. Lancer un test

Lancer un test n'est pas forcément la première chose que j'aurais présentée en temps normal. Cependant, dans le cas précis de RFW, cela vous permettra au fur et à mesure de ce tutoriel de lancer les exemples et d'analyser par vous-même les résultats, tout en vous laissant l'opportunité d'apporter des modifications et/ou d'essayer de nouvelles choses.

IV-A-1. Ligne de commande

Pour lancer un test, le mieux reste donc, comme précisé plus tôt, d'utiliser directement la ligne de commande.

Aussi, après vous être assuré que la commande « pybot » était bien reconnue par votre système (cas échéant, avisez), exécutez la commande suivante :

 
Sélectionnez
pybot <chemin vers votre fichier txt>

Votre test se lance alors. Trois fichiers seront alors d'office générés :

  • output.xml ;
  • log.html ;
  • report.html.

Cependant, vous pourriez vouloir « personnaliser » un peu le paramétrage de cette commande. Cela est tout à fait possible.

En effet la commande « pybot » dispose de nombreuses options. Nous allons voir ici les plus usuelles. Pour les restantes, je vous invite à vous plonger plus longuement dans la documentation RobotFramework.

Option

Description

-v, --variable <name:value>

Permet de fixer la valeur d'une variable à l'appel du test. Vous pouvez ainsi écrire un test générique et l'adapter à l'appel du test. Si vous avez besoin de plusieurs variables, il suffit de saisir autant de fois cette option que nécessaire.

-V, --variablefile <path:args>

Permet de passer un lot de variables simplement, de type Python. Le rôle est identique à l'option précédente : définir une ou plusieurs variables.

-d, --outputdir <dir>

Permet de préciser dans quel dossier on désire générer les fichiers de sortie.

-o, --output <file>

Permet de préciser un chemin spécifique pour le fichier output.xml.

-l, --log <file>

Permet de préciser un chemin spécifique pour le fichier log.html.

-r, --report <file>

Permet de préciser un chemin spécifique pour le fichier report.html.

-t, --test

Permet de stipuler les seuls test cases que l'on désire lancer.

-s, --suite

Permet de stipuler les seuls test suites que l'on désire lancer.

--pythonpath

Permet d'ajouter un chemin de recherche pour Python (bibliothèque et code).

--include <tag>

Permet d'inclure tous les test cases possédant ce tag.

--exclude <tag>

Permet d'exclure tous les test cases possédant ce tag.

--logtitle <title>

Permet de préciser un nom pour le fichier log.html.

--reporttitle <title>

Permet de préciser un nom pour le fichier report.html.

IV-B. Interpréter les résultats

IV-B-1. En ligne de commande

En ligne de commande, les messages renvoyés sont particulièrement pauvres et se limitent au strict minimum. Aussi la plupart du temps les messages sont-ils à peine suffisants pour déboguer.

Image non disponible

IV-B-2. Avec RIDE

Avec RIDE, les choses s'améliorent un peu. En effet, l'IDE RFW essaie de mettre un peu plus en évidence les zones de l'erreur, ainsi que la cause, même si cela n'est pas toujours très explicite.

Image non disponible

IV-B-3. Avec le fichier HTML

Généré systématiquement, que RFW ait été lancé via une ligne de commande ou via RIDE, le fichier HTML est réellement indispensable.

Il contient en effet tout ce qui se passe au cours des tests : les différentes valeurs d'une variable, retour de keywords, capture d'écran, log de dictionnaire…

Cet outil utilise également une coloration syntaxique afin de différencier les étapes se déroulant normalement, des autres.

Enfin, par défaut, seules les étapes en échec seront affichées, optimisant ainsi l'interprétation des fichiers de résultats de tests.

Image non disponible

IV-C. Structure des dossiers de test

RFW n'impose aucune contrainte particulière.

En effet, la ligne de commande dispose d'options permettant de paramétrer aussi bien les entrées que les sorties, assurant ainsi une très grande flexibilité. Vous pourrez aussi renommer les différents fichiers de sortie.

En bref, vous êtes libre d'arborer la structure de votre choix.

IV-D. Structure des fichiers de test

La structure d'un fichier de test RFW est toujours la même. Elle est constituée de maximum quatre sections, lesquelles peuvent être supprimées si inutiles.

 
Sélectionnez
*** Settings ***
Library            OperatingSystem
Library            BuiltIn
Resource            ressources.py

*** Variables ***
${message}        Hello, world!

*** Test Cases ***
My Test
        [Documentation]        Example test
        Log                ${message}
        My Keyword        /tmp

Another Test
        Should Be Equal        ${message}        Hello, world!

*** Keywords ***
My Keyword
    [Arguments]    ${path}
    Directory Should Exist        ${path}

La bibliothèque BuiltIn, est toujours sous-entendue, même s'il est préférable de l'importer explicitement.

Cet exemple est tiré du User Guide de RFW.

Chaque section est délimitée par son entête composé d'un titre entouré d'un jeu constitué d'un espace et de trois astérisques. Si une section ne contient rien, vous pouvez ne pas la déclarer (exception faite de « Test Cases » qui est obligatoire).

La première section, « Settings », permet d'importer les différentes bibliothèques et fichiers de ressource.

La seconde section, « Variables », permet de définir des variables pour les tests. Les variables déclarées dans cette section ne sont utilisables que dans le fichier.

La troisième section, « Test Cases » contient les différents cas de tests à créer.

Un test case se crée toujours de la même manière, à la fonction d'un bloc def Python. Sur la première ligne, au caractère 0, nous saisissons un titre pour le test. Ensuite, nous allons à la ligne, et nous indentons d'une tabulation (ou plus, il faut avoir une équivalence d'au moins deux espaces) le code de test. Nous pouvons y stipuler des options avant d'écrire explicitement le code. Si nous exécutons l'ensemble des test cases écrits, nous effectuons alors un test suite.

 
Sélectionnez
TitreDeMonTestCase
    [option1]    parametre
    Mon Keyword

Précisons que plusieurs test cases forment un test suite.

Enfin, la dernière section, « keywords », permet de créer de nouveaux keywords pour nos test cases. Il faut les assimiler à des fonctions. Ces dernières sont susceptibles d'être appelées de multiples fois dans nos tests. Plutôt que de les réécrire à chaque fois, nous les rentrerons dans cette section, puis nous nous contenterons d'y faire appel.

Notez que le texte n'a pas besoin d'être entouré de guillemets (voir « Hello, world ! » dans l'exemple. Par défaut dans RFW, toute variable est une chaîne de caractères.

IV-E. Import

IV-E-1. Ressources internes

Les seules ressources internes importables sont les bibliothèques vues précédemment (Built-in, Telnet…). On utilise le mot clé « Library » pour les importer :

 
Sélectionnez
*** Settings ***
Library    BuiltIn

IV-E-2. Ressources externes

Dans le cas d'une bibliothèque maison, par exemple la classe MyLib dans le fichier myproject.py dont le chemin d'accès serait com.mycompany.myproject, il faudra utiliser la notation suivante :

 
Sélectionnez
*** Settings ***
Library    com.mycompany.myproject.MyLib        WITH NAME    MyLib

Plus loin dans le code nous pourrons accéder aux différents keywords ainsi :

 
Sélectionnez
*** Keywords ***
My Keyword
    MyLib.Mon Keyword        argument

Dans le cas d'un fichier de ressources, généralement des variables prédéfinies, on utilisera le mot clé « Variables » :

 
Sélectionnez
*** Settings ***
Variables    mon_fichier.py

L'utilisation de « WITH NAME » permet d'obtenir un alias et équivaut au « as ».

IV-E-3. Règles de base

La notation RFW pour une variable est « ${nom_de_la_variable} ».

Par convention, le nom des variables sera constitué de minuscules, avec des underscores.

 
Sélectionnez
*** Variables ***
${message}        Hello, world!
${entier_42}      ${42}

IV-E-4. Fichier de variables

Les fichiers de variables ne sont rien de plus qu'un fichier à l'extension « .py » contenant des variables de type Python.

 
Sélectionnez
# -*- Coding: utf-8 -*- 

var01 = "Hello " 
var02 = "world!"

Et dans le fichier RFW :

 
Sélectionnez
*** Settings *** 
Variables        myvars.py 

*** Test Cases *** 
Test01 
    My Keyword 

*** Keywords *** 
My Keyword 
    Log        ${var01} ${var02}

Veuillez noter qu'ici les variables ne sont séparées que d'un espace. La concaténation de chaînes est implicite.

IV-E-5. Variables globales

La définition d'une variable globale se fait en deux temps. Tout d'abord la variable doit être définie dans la section « Variable » ou bien importée depuis un fichier de variables.

Ensuite, juste avant de quitter un espace de noms (un test case ou un keyword, dans RFW), il faut utiliser le keyword « Set Global Variable ».

 
Sélectionnez
*** Variables ***
${var}        3

*** Test Cases ***
Test01
    Log    ${var}
    My Keyword
    Log    ${var}

*** Keywords ***
My Keyword
    ${var} =    Set Variable    5
    Set Global Variable    ${var}

Si vous exécutez ce code, vous verrez qu'avant l'appel du keyword, « var » vaut 3, et qu'après il vaut 5. Supprimez maintenant le « Set Global Variable » (ou mettez la ligne en commentaire avec « # »), et relancez le test.

Maintenant, « var » vaut toujours 3. Nous retombons en fait dans l'équivalent des espaces de noms en Python.

IV-E-6. Variables intégrées

Il existe un certain nombre de variables fournies et préconfigurées par défaut. Voici les plus usuelles.

Variable

Description

${CURDIR}

Chemin absolu du dossier où se trouvent les fichiers de test.

${TEMPDIR}

Chemin absolu du dossier temporaire de l'OS.

${EXECDIR}

Chemin absolu du dossier d'où est exécutée la commande pybot.

${/}

Caractère de séparation pour les chemins, varie selon l'OS.

${:}

Caractère de séparation de chemin, varie selon l'OS.

${\n}

CRLF ou LF selon l'OS.

${SPACE}

Chaîne de caractères contenant un seul espace.

${EMPTY}

Chaîne de caractères vide.

Ces variables s'utilisent comme n'importe quelle variable que vous auriez vous-même définie.

IV-E-7. Listes et dictionnaires

Les listes et les dictionnaires se créent via des keywords dédiés. Nous allons voir ici deux exemples de création :

 
Sélectionnez
*** Settings *** 
Library     BuiltIn 
Library        Collections 
 
*** Test Cases *** 
CreationListe 
    ${list} =    Create List        a    b    c    d 
    Log        ${list} 
    ${tmp} =    Get From List    ${list}        0 
    Log        ${tmp} 

CreationDict 
    ${dict} =    Create Dictionary    a    1    b    2 
    Log        ${dict} 
    ${tmp} =    Get From Dictionary        ${dict}        a     
    Log        ${tmp}

Vous remarquerez ici que l'on ne peut logger directement un extract de liste ou de dictionnaire. Il faut obligatoirement passer par une variable temporaire. Il en est de même avec le [Return] des keywords.

IV-F. Keyword

Par définition un keyword est assimilable à une fonction. Il réalise une ou plusieurs tâches, prend ou non en entrée des paramètres et renvoie ou non des valeurs en sortie.

Un keyword peut être constitué de plusieurs autres keywords. Cela complique alors la tâche de l'interpréteur pour faire la distinction entre keywords et variables/paramètres.

Pour pallier cela, la règle définie est que le caractère de séparation est au moins un double espace ou une tabulation équivalente à au moins un double espace.

Aussi, tout mot séparé d'un seul espace sera considéré comme faisant partie d'un tout, avec le mot précédent. À partir de deux espaces, cela sera considéré comme une séparation.

Chaque keyword est capitalisé, c'est-à-dire que la première lettre de chaque mot est mise en majuscule, le reste en minuscules.

Si plusieurs Keywords portent le même nom, alors un message de conflit sera affiché, et l'exécution du test s'arrêtera. Dans ce cas, la solution consistera simplement à faire préfixer le keyword de sa bibliothèque.

IV-F-1. Les principaux fournis

Je vais ici vous dresser la liste des keywords les plus utiles, et vous les décrire rapidement. Pour de plus amples informations, notamment leur usage, je vous renvoie vers les documentations officielles. Je ne peux que vous inviter à les lire en entier pour vous en imprégner.

Bibliothèque

Keyword

Description

Builtin

Create List

Permet de créer une liste.

Evaluate

Permet d'exécuter une commande Python basique.

Fail

Fait tomber le test en échec.

Get Count

Permet de compter le nombre d'occurrences d'un élément donné dans un autre élément.

Get Length

Permet de connaître la taille d'un élément (liste, string…).

Log

Permet de logger une information, une variable…

Run Keyword And Continue On Failure

Lance un keyword donné, et n'arrête pas le test si ce dernier tombe en échec.

Run Keyword And Ignore Error

Lance un keyword donné et continue même si une erreur est levée.

Run Keyword If

Lance un keyword donné uniquement si une condition est remplie.

Set Variable

Permet d'assigner une variable.

Should Be Equal

Permet de vérifier une égalité.

Should Contain

Permet de s'assurer qu'un élément en contient bien un autre.

Should Match Regexp

Permet de s'assurer qu'un élément correspond bien à une REGEX de référence.

Should Not Be Equal

Permet de vérifier une différence.

Should Not Contain

Opposé de « Should Contain ».

Should Not Match Regexp

Opposé de « Should Match Regexp ».

Sleep

Permet de mettre le test en sommeil.

Collections

Append To List

Permet d'ajouter des entrées à une liste.

Combine Lists

Permet de fusionner deux listes.

Count Values In List

Permet de compter le nombre d'occurrences d'un élément dans une liste.

Create Dictionary

Permet de créer un dictionnaire.

Dictionary Should Contain Item

Permet de vérifier qu'un dictionnaire contient un item donné.

Dictionary Should Contain Key

Permet de vérifier qu'un dictionnaire contient une clé donnée.

Dictionary Should Contain Value

Permet de vérifier qu'un dictionnaire contient une valeur donnée.

Dictionary Should Not Contain Key

Opposé de « Dictionary Should Contain Key ».

Dictionary Should Not Contain Value

Opposé de « Dictionary Should Contain Value ».

Get From Dictionary

Permet de récupérer un élément du dictionnaire.

Get From List

Permet de récupérer un élément de la liste.

List Should Contain Value

Permet de s'assurer qu'une liste contient bien une valeur donnée.

Lists Should Be Equal

Permet de comparer deux listes.

Remove From Dictionary

Permet de supprimer une entrée dans un dictionnaire.

Remove From List

Permet de supprimer une entrée dans une liste.

String

Convert To Lowercase

Permet de convertir une chaîne de caractères en minuscules.

Convert To Uppercase

Permet de convertir une chaîne de caractères en majuscules.

Get Substring

Permet d'extraire une partie de la chaîne de caractères.

Replace String

Permet de substituer un lot de caractères par un autre dans une chaîne de caractères.

Should Be String

Permet de s'assurer qu'un élément est bien une chaîne de caractères.

Split String

Permet de splitter une chaîne de caractères.

Operating System

Copy Directory

Permet de copier un dossier.

Copy File

Permet de copier un fichier.

Create Directory

Permet de créer un dossier.

Create File

Permet de créer un fichier.

Directory Should Be Empty

Permet de vérifier que le dossier est vide.

Directory Should Exist

Permet de vérifier que le dossier existe.

File Should Exist

Permet de vérifier que le fichier existe.

Get File

Permet de lire le contenu d'un fichier.

Get File Size

Permet de connaître la taille d'un fichier.

Join Path

Permet d'effectuer l'équivalent d'un os.path.join().

Remove Directory

Permet de supprimer un dossier.

Remove File

Permet de supprimer un fichier.

Run

Permet de lancer une commande système (DOS/SHELL).

Dialogs

Execute Manual Step

Permet d'afficher un message à l'utilisateur et attend sa confirmation pour continuer.

Get Value From User

Permet de demander une valeur à l'utilisateur.

IV-F-2. Personnalisés

Ce que nous appellerons des keywords personnalisés désignent en fait ceux que nous écrirons dans la section « Keywords » qui sera présentée plus loin.

 
Sélectionnez
*** Settings *** 
Library        BuiltIn 

*** Test Cases *** 
Cas1 
    ${result}=        Mon Keyword        2 

*** Keywords *** 
Mon Keyword 
    [Arguments]        ${arg1} 
    Log        ${arg1} 
    ${tmp}=        Evaluate    int('${arg1}') * 2 
    [return]    ${tmp}

Dans cet exemple, nous pouvons voir l'usage de certaines options décrites ci-après.

Ce que nous noterons ici, est la façon dont on utilise les variables dans du code Python. N'oublions pas en effet que RobotFramework traite les variables comme des chaînes de caractères.

Nous pouvons également voir comment utiliser les keywords personnalisés.

IV-F-3. Options

Il existe un certain nombre d'options pour les keywords. Ces options s'écrivent entre crochets, et sont suivies de leurs arguments.

Options

Description

[Documentation]

Permet de documenter le keyword.

[Timeout]

Permet d'ajouter un timeout de sécurité. Passé ce délai, le keyword tombe en échec.

[Arguments]

Permet de stipuler les arguments attendus et leurs éventuelles valeurs par défaut.

[Teardown]

Permet d'appeler un autre keyword à la fin du keyword en cours. Par définition, un teardown est une opération permettant de remettre notre environnement de tests dans l'état dans lequel il se trouvait avant nos tests.

[Return]

Permet d'effectuer l'équivalent d'un return Python.

Contrairement aux test cases et test suites, les keywords ne disposent pas d'options [Setup].

IV-G. Boucles et condition

IV-G-1. FOR

Les boucles FOR sont un peu particulières en RFW. Leur utilisation est proche du FOR Python, mais elles sont peu pratiques à coder. Cependant, cela peut s'avérer utile dans certains cas.

 
Sélectionnez
*** Settings ***
Library     BuiltIn
Library        Collections

*** Test Cases ***
TestCase01
    My Keyword 01
    My Keyword 02

*** Keywords ***
My Keyword 01
    :FOR    ${animal}    IN    chat    chien
    \        Log        ${animal}
    \        Log        Animal enregistre

My Keyword 02
    ${ma_liste} =    Create List        chat    chien
    :FOR    ${item}        IN        @{ma_liste}
    \        Log        ${item}

Comme on peut le voir dans « My Keyword 02 », il faut remplacer « $ » par « @ » lorsqu'on parcourt une liste avec une boucle FOR.

Je vous invite à laisser le « $ » afin de constater ce que cela vous renvoie.

IV-G-2. FOR…IN RANGE

À l'instar de Python, sur lequel il se base, RFW dispose également d'un FOR… IN RANGE.

 
Sélectionnez
*** Settings *** 
Library     BuiltIn 

*** Test Cases *** 
TestCase01 
    My Keyword 01 

*** Keywords *** 
My Keyword 01 
    :FOR    ${number}    IN RANGE    2    9    3 
    \        Log        ${number}

Comme nous pouvons le voir dans cet exemple, le fonctionnement est identique à Python : start, stop, step.

Vous pouvez quitter une boucle avec le keyword « Exit For Loop ».

IV-G-3. IF

Il existe plusieurs keywords associés au IF. La plupart correspondent à un prédicat prédéfini (Continue For Loop If, Set Variable If…). Je vous renvoie vers la documentation de la bibliothèque Built-In pour en prendre connaissance.

Le keyword équivalent à un IF Python est « Run Keyword If ». Comme le laisse suggérer ce keyword, nous n'allons pas exécuter un code, mais appeler un Keyword, lequel contiendra le code que nous désirons exécuter.

 
Sélectionnez
*** Settings ***
Library     BuiltIn

*** Test Cases ***
TestCase01
    My Keyword 01

*** Keywords ***
My Keyword 01
    :FOR    ${number}    IN RANGE    2    12    3
    \        Log        ${number}
    \        Run Keyword If        '${number}' == '8'        Exit For Loop

Bien qu'il existe la possibilité de faire un ELSE ou encore un ELSE IF, je vous recommanderais plutôt de faire plusieurs Run Keyword If, qui à l'usage se révèlent moins capricieux.

IV-H. Test Case

Les cas de test ou « test case » constituent les tests basiques et sont assimilables à des tests unitaires. Ils constituent la base de robotframework.

IV-H-1. Options

On peut définir certaines options sur les test cases. Voici les principaux :

Option

Description

[Documentation]

Permet de documenter un test case.

[Arguments]

Permet de stipuler les arguments attendus et leurs potentielles valeurs.

[Timeout]

Permet de stipuler un timeout. Ce délai écoulé, si le test case n'est toujours pas fini, il tombera en échec.

[Setup]

Permet d'appeler un keyword qui sera exécuté avant le test case.

[Teardown]

Permet d'appeler un keyword qui sera exécuté après le test case.

[Tags]

Permet de déclarer des tags, qui peuvent servir lors de l'exécution.

 
Sélectionnez
MyTestCase
    [Documentation]    Voici comment documenter un test case
    [Tags]    demo
    [Arguments]        Arg1        Arg2="hello"
    Log    Arg1
    Log    Arg2

IV-I. Test Suite

Les suites de tests ou « test suite » sont constituées d'un ensemble de test cases. L'assemblage de ces test cases peut s'effectuer au sein d'un fichier ou d'un dossier (on y créera alors un fichier __init__.txt).

IV-I-1. Options

Tout comme pour les test cases, on peut définir des options pour les test suites. Cependant, un test suite pouvant prendre différentes formes (fichier ou dossier), la façon de faire peut varier.

Dans le cas d'un dossier, cela est fort simple, puisqu'il s'agit alors de créer un fichier __init__.txt, puis d'y entrer tout ou partie des options suivantes :

Option

Description

[Documentation]

Permet de documenter un test case.

[Suite Setup]

Permet d'appeler un keyword qui sera exécuté avant le test suite.

[Suite Teardown]

Permet d'appeler un keyword qui sera exécuté après le test suite.

[Test Timeout]

Permet de stipuler un timeout. Ce délai écoulé, si le test suite n'est toujours pas fini, il tombera en échec.

 
Sélectionnez
[Documentation]    Documentation du test suite
[Suite Setup]    Setup Du Test Suite
[Test Timeout]    60s

Si le test suite consiste en un fichier, on peut utiliser les mêmes options, mais celles-ci seront à déclarer en début de fichier dans la section Settings (voir plus loin).

IV-J. Écrire ses tests

IV-J-1. Mode verbeux

L'écriture de tests en mode verbeux correspond aux exemples vus jusqu'ici. Il s'agit donc d'un simple fichier texte, découpé en quatre sections, et utilisant comme caractère de séparation la tabulation.

Lorsque vous êtes en mode verbeux, oubliez la notion d'objet, car celle-ci n'existe alors plus.

IV-J-2. Mode Python

Il n'existe pas vraiment de mode Python pour écrire des tests. Ce que l'on fait en vérité, c'est écrire des bibliothèques, et simplement y faire appel depuis un fichier RFW en mode verbeux.

Je vous renvoie donc vers la section bibliothèques Python, ci-après pour savoir comment faire.

IV-K. Écrire ses bibliothèques

IV-K-1. Mode verbeux

Écrire une bibliothèque en mode verbeux n'est pas compliqué en soi. En fait, une bibliothèque RFW n'est rien d'autre qu'un fichier test RFW que l'on peut importer dans un autre fichier de test RFW.

ma_lib.txt
Sélectionnez
*** Settings *** 
Library     BuiltIn 

*** Keywords *** 
My External Keyword 
    Log        Je log ici depuis un keyword importé
test.txt
Sélectionnez
*** Settings *** 
Library     BuiltIn 
Resource    ma_lib.txt 

*** Test Cases *** 
TestCase01 
    My Keyword 01 
    My External Keyword 

*** Keywords *** 
My Keyword 01 
    :FOR    ${number}    IN RANGE    2    12    3 
    \        Log        ${number} 
    \        Run Keyword If        '${number}' == '8'        Exit For Loop

Si la bibliothèque à importer n'est pas dans le même dossier, vous pouvez indiquer ou le chemin relatif, ou le chemin absolu.

IV-K-2. Mode Python

L'écriture d'une bibliothèque RFW repose sur des concepts basiques de Python. Il y aura cependant quelques subtilités que nous allons voir ici.

Pour commencer, le point d'entrée côté RFW s'effectuera au niveau d'une classe. Vos bibliothèques en contiendront donc toujours. Les méthodes de ces classes constitueront les keywords.

Le nom des méthodes s'écrira en minuscules et avec des underscores, côté Python. Une fois importés côté RFW, les différents mots seront capitalisés et les underscores remplacés par un simple espace.

Si un nom de méthode commence par un underscore, il sera considéré comme privé, et donc non accessible depuis RFW.

Côté paramètres, à moins que vous n'ayez créé un élément spécifique (liste, dictionnaire) ou ayez utilisé la notation spécifique entier (rappel : ${mon_entier}), tout paramètre sera passé en tant que chaîne de caractères.

De manière similaire à Python, vous pouvez utiliser *args et **kwargs.

Si l'on désire logger quelque chose dans le fichier de sortie, il suffit d'effectuer un simple print.

Fichier 1 :

ma_lib_python.py
Sélectionnez
# -*- Coding: utf-8 -*-

__all__ = ['MaClass']

class MaClass:

    def __init__(self):
        pass

    def mon_keyword_perso(self, texte):
        print "voici comment imprimer dans le log.html"
        return "le texte etait: %s" % (texte)

Fichier 2 :

test.txt
Sélectionnez
*** Settings ***
Library           BuiltIn
Library           ma_lib_python.MaClass

*** Test Cases ***
TestCase01
    My Keyword 01
    My Keyword 02

*** Keywords ***
My Keyword 01
    : FOR    ${number}    IN RANGE    2    12    3
    \    Log    ${number}
    \    Run Keyword If    '${number}' == '8'    Exit For Loop

My Keyword 02
    ma_lib_python.MaClass.Mon Keyword Perso    Hello, world!

À partir du moment où vous voulez utiliser du code Python, qu'il s'agisse d'une bibliothèque ou bien du code à tester, il vous faudra utiliser l'option « --pythonpath » dans l'appel de pybot, afin de préciser où chercher le code et/ou la bibliothèque. Vous pouvez également donner le chemin complet directement, en absolu ou relatif.

IV-L. Quelques règles complémentaires

Outre les règles déjà vues jusqu'ici, il faut prendre en compte les points suivants :

  • un ensemble de test cases constitue un test suite ;
  • un dossier contenant des test cases forme un test suite ;
  • un dossier test suite peut contenir des sous-dossiers eux-mêmes test suites ;
  • les fichiers/dossiers commençant par « . » ou « _ » seront ignorés ;
  • les dossiers contenant « CVS » dans leur nom seront ignorés ;
  • les fichiers de tests doivent avoir une extension reconnue (.txt recommandée) ;
  • par défaut, RFW traite toutes les variables comme du texte.

V. Mise en pratique

Il est intéressant de lire de la théorie, mais comme d'habitude, rien ne vaut un exemple pratique pour assimiler les points étudiés et lever les dernières interrogations.

Imaginons un projet extrêmement basique : créer un module contenant des fonctions pour effectuer des opérations sur des nombres et les chaînes de caractères. Les fonctions seront basiques (puissance, addition, soustraction, concaténation) et seront mises à disposition via une classe.

code.py
Sélectionnez
# -*- Coding: utf-8 -*- 

class MaClass(object): 
    def __init__(self): 
        pass 

    def puissance_deux(self, nb): 
        return int(nb)**2 

    def addition(self, nb1, nb2): 
        return nb1 + nb2 

    def soustraction(self, nb1, nb2): 
        return int(nb1) - float(nb2) 

    def concatenation(self, mot1, mot2): 
        return mot1 + mot2 

if __name__ == "__main__": 
    pass

Maintenant, il va falloir nous assurer que notre code réagit conformément à nos attentes. Nous allons donc créer un fichier de test RFW.

test.txt
Sélectionnez
*** Settings *** 
Library        BuiltIn 
Resource        my_lib_rfw.txt    #bibliothèque RFW 
Library        ma_lib.my_lib_python.MaClasseDeTest        WITH NAME    MCDT    # bibliothèque Python de test 
Library        code.MaClass    # Code à tester 
Variables    vars.py 

*** Variables *** 
${pi}        ${3.14} 

*** Test Cases *** 
Test_p2 
    [Documentation]        TU de la puissance de 2 
    [Tags]        puissance        tout 
    ${result} =        code.MaClass.Puissance Deux        2 
    Should Be Equal        ${result}        ${4} 
     
Test_addition 
    [Documentation]        TU de l'addition 
    [Tags]        addition        tout 
    ${result} =        code.MaClass.addition    ${2}    ${3} 
    Should Be Equal        ${result}        ${5} 

Test_soustraction 
    [Documentation]        TU de la soustraction 
    [Tags]        soustraction        tout 
    ${result} =        code.MaClass.soustraction    8    4.86 
    Should Be Equal        '${result}'        '${pi}' 
    MCDT.Should Be Same Type    '${result}'        '${pi}' 

Test_concatenation 
    Concatenons Hello World 

Test_egalite 
    ${result} =        Equal Or Not    2    5 

*** Keywords *** 
Concatenons Hello World 
    ${return} =        code.MaClass.concatenation        ${mot1}        ${mot2} 
    Should Be Equal        '${return}'        'Hello, world!'

Comme nous avons pu le constater dans le fichier texte, nous allons utiliser une bibliothèque maison de type RFW, une autre de type Python, ainsi qu'un fichier de variables

my_lib_rfw.txt
Sélectionnez
*** Settings *** 
Library        BuiltIn 

*** Keywords *** 
Equal Or Not 
    [Arguments]        ${arg1}        ${arg2} 
    Log        ${arg1},${arg2} 
    ${tmp} =    Run Keyword If    '${arg1}' == '${arg2}'    Set Variable    Equal    ELSE    Set Variable    Not Equal 
    [Return]    ${tmp}
my_lib_python.py
Sélectionnez
class MaClasseDeTest(object): 
    def __init__(self): 
        pass 

    def should_be_same_type(self, elmt1, elmt2): 
        type1 = type(elmt1) 
        type2 = type(elmt2) 
         
        if type1 is type2: 
            return True 
        else: 
            return False
Vars.py
Sélectionnez
mot1 = "Hello," 
mot2 = " world!"

L'ensemble de ces fichiers seront à placer dans un dossier. Le fichier « my_lib_python.py », sera placé dans un sous-dossier nommé « ma_lib », lequel contiendra également un fichier « __init__.py » vide.

Image non disponible

Maintenant, voyons comment lancer la commande de différentes façons.

 
Sélectionnez
# Lancement standard, on precise ou trouver les bibliotheques Python :
pybot --pythonpath ./ test.txt

# Lancement avec tri par tag :
pybot --include puissance --pythonpath ./ test.txt 

# Lancement d'un test en particulier :
pybot --pythonpath ./ --test Test_concatenation test.txt

Ces trois commandes produisent les résultats suivants

Image non disponible Image non disponible

Image non disponible

Image non disponible

Image non disponible

Image non disponible

Nous pouvons bien voir à travers ces exemples quelques-unes des possibilités de gestion des tests offertes par Robotframework.

Bien entendu, ceci n'est qu'un petit échantillon. Néanmoins, j'ose espérer que cela constitue déjà un minimum afin de l'appréhender.

VI. Conclusion

Comme nous venons de le voir, Robotframework est un puissant outil de test capable de se mettre à la portée de tous.

Une personne ne s'y connaissant pas en programmation est capable d'écrire des tests basiques en utilisant la version simple, très verbeuse.

La version complète convient aux développeurs en leur offrant la possibilité de coder des tests complets et/ou des keywords directement en Python.

Dans tous les cas, il permet l'écriture rapide de jeux de tests, et ses rapports, à la fois complets et explicites ne pourront qu'être un argument supplémentaire en sa faveur.

VII. Remerciements

Je voudrais remercier les personnes suivantes pour leur aide dans l'écriture de ce tutoriel :

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Licence Creative Commons
Le contenu de cet article est rédigé par Alexandre GALODE et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2015 Developpez.com.