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▲
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 ».
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 :
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.
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.
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.
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.
*** 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.
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 :
***
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 :
***
Settings ***
Library com.mycompany.myproject.MyLib WITH NAME MyLib
Plus loin dans le code nous pourrons accéder aux différents keywords ainsi :
***
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 » :
***
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.
***
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.
# -*- Coding: utf-8 -*-
var01 =
"Hello "
var02 =
"world!"
Et dans le fichier RFW :
***
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 ».
***
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 :
***
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.
***
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.
***
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.
***
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.
***
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. |
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. |
[Documentation] Documentation du test suite
[Suite Setup] Setup Du Test Suite
[Test Timeout] 60
s
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.
***
Settings ***
Library BuiltIn
***
Keywords ***
My External Keyword
Log Je log ici depuis un keyword importé
***
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 :
# -*- 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 :
***
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.
# -*- 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.
***
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
***
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}
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
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.
Maintenant, voyons comment lancer la commande de différentes façons.
# 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
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 :