Automatiser le non-automatisable

Publié par Xavier Renaudin, le 17/02/2012, dans Test, Tutoriel

 

“Individuals and interactions over processes and tools”, Agile Manifesto

 

Dans un projet, la période la plus stressante est en général la mise en production et un des problèmes qui se pose de façon récurrente est la validation de la non-régression.
Une des solutions qui s’impose intuitivement est la mise en place de tests automatisés mais celle ci peut coûter cher et parfois les outils utilisés ne conviennent pas.
Et bien pour tous les cas où l’automatisation semble être impossible, il existe un petit logiciel gratuit du nom de Sikuli qui permet d’automatiser le non-automatisable.

Kesako Sikuli ?

Sikuli est un outil gratuit et open-source qui permet de scripter des actions utilisateurs en se basant sur la reconnaissance d’image à partir de copies d’écran. Il utilise des scripts en Jython (fils caché du Java et du Python) et est fourni avec un IDE qui facilite l’édition des scripts et la capture des copies d’écran.
Pour avoir des idées de possibles utilisations vous pouvez aller voir les exemples sur le blog de Sikuli ou simplement taper Sikuli sous YouTube.
Dans ce post, je vais plutôt expliquer comment j’ai tenté d’intégrer Sikuli dans un contexte un minimum industrialisé.

Pour quoi ?

Sikuli peut répondre à plusieurs cas de figure :
  • Automatiser des scénarios pour une application
  • Automatiser les interactions entre plusieurs applications (même des applications tierces)
  • Automatiser le lancement et la vérification de tests automatisés

exemples d’utilisation dans mon cas :

  • Tester l’interaction d’éléments Flash dans une page Web
  • Vérifier les mails envoyés par l’application dans un outil externe type Outlook ou Gmail
  • Intégrer au build continu et vérifier des captures d’écran faites sur IPhone avec UIAutomation

Pour qui ?

Même si l’écriture de script peut être très simple, dès lors que l’on veut faire des choses un petit peu sérieuses, des connaissances en programmation vont être requises. Il manque clairement un générateur de code si on voulait pouvoir le mettre entre toutes les mains, mais avec un minimum de bonne volonté, on peut s’en sortir sans trop de galère.

Comment ?

Je ne vais pas m’attarder sur le fonctionnement de Sikuli, la documentation sur le site est suffisante pour qui veut commencer à s’amuser avec, mais je vais tout de même expliquer l’utilisation nominale en quelques mots :
  1. Avec l’IDE fourni après l’installation de Sikuli on crée un nouveau script
  2. L’IDE permet d’ajouter facilement au script des étapes comme “Click(<une image>)” ou “Wait(<une image>)”. La récupération des images se faisant dans un mode où la souris permet de capturer une zone de l’écran.
  3. Le script ainsi créé est sauvegardé dans un répertoire de type “monScript.sikuli” qui contient le script python et les images capturées.
Sikuli first script

 

A partir de là un univers infini de possibilité s’ouvre à nous !!!
Mais j’ai pour ma part expérimenté quelques déboires dont certains peuvent être évités assez simplement une fois qu’on sait comment.
La chose la plus importante à garder en tête est que le coût des tests automatisés vient de la mise en place et surtout de la maintenance.
Donc ce que je peux vous conseiller est de commencer par faire des scripts le plus simples possible en terme d’écriture et le plus unitaires possible en terme de portée fonctionnelle, ce qui vous permettra de les jeter s’ils deviennent obsolètes et d’en réécrire de nouveau sans trop déprimer. De même si vous vous retrouver à tester plusieurs fois les mêmes actions, pensez à extraire ces actions dans un script à part et à l’importer comme décrit plus bas.

 

1- Structurer l’arborescence :

Comme on l’a vu, chaque script génère un dossier contenant ses fichiers propres, du coup l’arborescence se crée d’elle même.
Par contre pour centraliser les images utilisées par plusieurs scripts, il peut être pratique de regrouper ces images dans un répertoire de votre choix.
Pour ce faire il est possible de modifier le chemin des images utilisées par le script avec la commande suivante :
setBundlePath("C:\\TESTS\\assets")
La doc officielle (ndla : une nouvelle version de la doc est arrivée que je n’ai pas encore testée)

Après quoi on accède à une image avec la chaine de caractère représentant son chemin en relatif :

exists ("monImage.png") # permet de vérifier si l'image est visible à l'écran
De même certaines fonctions ou paramètres doivent pouvoir être partagés et donc il est bon de les regrouper dans des scripts selon leur utilité et de façon à pouvoir les retrouver facilement.
Pour importer un autre script il suffit de rajouter la ligne suivante au début de son script :
import mon_autre_script
Par contre il faudra penser à rajouter la ligne suivante dans les scripts qui sont susceptibles d’être importés :
from sikuli.Sikuli import *
Et vous pouvez aussi récupérer le chemin des images utilisées (fixé par le setBundlePath depuis n’importe quel script) avec la commande suivante :
myPath = os.path.dirname(getBundlePath())
if not myPath in sys.path: sys.path.append(myPath)

2- Structure des fichiers de tests

Sikuli étant basé sur du Python, il est possible d’utiliser le framework unittest pour utiliser les scripts Sikuli comme des tests fonctionnels.

 

Sikuli Test Framework

 

Le framework est assez standard, donc si vous n’avez jamais fait de tests automatisés, je vous encourage à lire la documentation, le tout étant assez standard.

 

Pour pouvoir utiliser le framework il faut déjà ajouter au début du script
import unittest
Ensuite on déclare une classe (on va l’appeler “TestScenario”)
class TestScenario(unittest.TestCase):
Dans cette classe on ajoute les méthodes standards setUp (déclenchée au lancement de la suite de test) et tearDown (déclenchée à la fin)

 

def setUp(self):
# code...
def tearDown(self):
# code...

 

Ensuite on ajoute dans la classe les méthodes qui contiendront les tests. Ces méthodes doivent être indépendantes (elles ne sont pas forcément lancées dans un ordre défini)
(Notez que le nom de ces methodes doit commencer par “test”)

 

def testScenario1(self):
# ...

 

Dans ces méthodes de tests, on peut utiliser la méthode assert() de Sikuli ou les méthodes d’assertion de Python
Ici un exemple qui vérifie que monImage.png existe sur l’écran :
assert (exists ("monImage.png"))
Le test continuera si l’image existe, sinon il s’arrêtera en échec et passera aux autres tests de la classe.

 

3- Intégrer au Continuous Build

Après avoir écrit ses tests, le mieux c’est de pouvoir les lancer de façon automatique. Pour ce faire je vais vous montrer comment faire l’intégration au Build via Jenkins.
Et comme la majorité des gens est encore sous Windows, et que nos tests doivent simuler ce que fait  la majorité des gens, je vais m’attarder sur cette plateforme (je sais Jenkins sous Windows ça fait peur…)

 

Donc la première chose à faire sera de trouver une machine sous Windows (virtuelle ou pas) qui n’est utilisée par personne d’autre et qui pourra lancer Sikuli de façon périodique.
Ensuite on installe Jenkins avec les quelques trucs qui suivent :
  • Il faut permettre au service d’interagir comme un utilisateur :
    “Dans Administrative Tools-> Services, clique droit sur le service Apache Tomcat qui correspond à Hudson -> Properties. Dans l’onglet “Log On”, on coche la case “Allow service to interact with desktop”. On redémarre le service.” (cf. https://answers.launchpad.net/sikuli/+question/153455)
  • Il faut ajouter “<path-to-sikuli>\libs” et “<path-to-java>\jre6\bin” dans le system path et dans le PATH de Jenkins (page “configure”)
  • Il faut rajouter ce patch : http://www.microsoft.com/download/en/details.aspx?displaylang=en]Microsoft&id=5582
Il suffit ensuite de créer un job Jenkins qui lance Sikuli en ligne de commande (%SIKULI_SCRIPT_PATH% étant une variable d’environnement contenant le chemin absolu de mes scripts) :
call Sikuli.bat -r %SIKULI_SCRIPT_PATH%/TestScenario.sikuli
et voilà !

 

4- Autres trucs en vrac

De façon général si vous voulez avoir une gestion de l’utf-8 il suffit de rajouter la ligne suivante en haut de vos scripts :
#coding: utf-8

Il est possible d’écrire simplement dans la sortie avec :

print ("Mon message")

Si votre script ne semble pas fonctionner alors qu’il devrait, penser à rajouter des pauses après chaque action. En effet l’ordinateur peut être beaucoup plus rapide que vous et parfois il va simplement trop vite. Pour le faire attendre 2 secondes utiliser la commande suivante :

wait(2)

Et pour ceux qui veulent se faciliter la vie et les copies d’écran sans passer par l’IDE  : PrtScr

Conclusion

(+) :
– Complètement cross-plateforme et cross-produit
– Décorrélé du code et n’implique pas de connaître la techno des outils qu’on veut tester.
– Permet de rester très haut niveau et de se mettre à la place d’un utilisateur (si c’est trop compliqué à scripter, c’est peut être juste trop compliqué comme fonctionnalité)
– Basé sur du Jython et en open source il peut être associé à d’autres outils (ex : avec Selenium, avec RobotFramework)

(-) :
– Le plus long est de trouver la bonne copie d’écran (pour le web, le rendu des différents navigateurs peut multiplier les copies d’écran)
– La maintenance peut être rude (Si c’est le cas passez à autre chose ou simplifiez)
– Il manque un générateur de code “click by click” (Si ça intéresse quelqu’un : https://answers.launchpad.net/sikuli/+question/136146)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

By submitting this form, you accept the Mollom privacy policy.