Web qualité - Blog d'un testeur
Blog sur la qualité en général, et l'automatisation de test web en particulier
Affichage des résultats de tests
Lorsqu'on teste avec jenkins, cucumber et watir, on obtient des rapports détaillés, qu'il faut lire et analyser en permanence.
Depuis plusieurs mois, nous avons dans nos locaux une télé dédiée à l'affichage de l'état général de l'ensemble de nos tests. Pour cela, le plugin Jenkins Wall Display nous a suffit dans un premier temps. Nous affichons sur la télé une page web qui fait défiler
Au total, sur ces écrans, nous affichons le résumé :
- Plus de 1 300 test php unit (et leur 5 000 assertions)
- Près de 500 tests unitaires JS
- Plus de 950 scénarios cucumber pour les tests fonctionnels.
En outre, nous affichons aussi quelques graphiques sensibles de l'état de la production : nombre de compte crées, etc..
On a beau regrouper toutes ces informations, il arrive un moment où l'affichage n'est plus lisible.
Le constat est moins alarmant pour les tests unitaires. Les chiffres exposent bien pourquoi :
- Tests fonctionnels : 40 jobs jenkins * 3 navigateurs
- Tests unitaires : 18 jobs jenkins * 2 environnement
Comment afficher proprement les résultats
Je suis parti en quête d'une solution pour afficher tous nos résultats proprement, avec quelques contraintes :
- Je préférais afficher tous les résultats sur un seul écran par type de tests
- Je veux pouvoir afficher un résumé ( x tests KO / x tests total)
- Je veux pouvoir séparer facilement les affichages d'un même type de tests (par navigateur / environnement)
Ma quête fut longue et semée d'embûches :
- Tentative d'utilisation de l'API, mais c'était déjà trop lent alors que je ne calculais / affichais pas la moitié de ce que je voulais (45 secondes environ)
- Plusieurs plugin jenkins, mais aucun ne permettant ce que je veux
- Un Plugin jenkins faisant la moitié de ce que je voulais, mais complètement bugué
Mon premier plugin jenkins
Je suis donc parti à l'assaut de la documentation de jenkins pour coder un plugin fait-maison qui ferait exactement ce que je voudrais.
Ce que j'ai bien aimé dans cette création :
- Tout en java. Je n'avais pas codé en java depuis 10 ans je pense, et j'ai perdu, mais vite repris mes repères.
- Bosser sur un plugin que je pourrais diffuser en open-source à la fin :)
- La possibilité de faire exactement ce que je veux, sans être limité par un plugin déjà fait.
Ce que je n'ai pas aimé :
- La documentation : elle existe, elle semble complète. Mais je trouve l'organisation moyennement bonne. J'ai plusieurs fois été à la recherche d'exemple de code pour trouver la fonction dont j'avais besoin, que je ne trouvais pas dans la doc.
- L'installation de maven qui marche du premier coup sur un de mes postes, mais se passe mal sur l'autre.
Au final, ça donne quoi ?
J'ai donc un plugin qui permet de créer une nouvelle "View". On peut y configurer :
- Les noms des colonnes, et la façon de filtrer les jobs dans chaque colonne, par des expression régulières.
- Affichage dans chaque colonne du temps pris pour ces tests, du nombre de scénarios en échec et du nombre total de scénarios. (Afficher le nombre de jobs est beaucoup plus simple, mais donne beaucoup moins d'informations : un job en échec pour 1 / 34 est moins grave qu'un test avec 4 / 4 erreurs)
- Affichage de la liste des jobs en échec (avec le nombre de scénarios)
- Une colonne à part, qui affiche le temps total sur jenkins (master + slave)
- Une liste de jobs spéciaux (dans mon cas : ceux qui lancent les autres, la génération de la doc...)
Le plugin est sur github : https://github.com/fabrice31/CucumberJenkins
Et maintenant ?
J'ai configuré le plugin pour fonctionner avec cucumber, puisque je suis au coeur des tests fonctionnels. Il faut maintenant que je me débrouille pour que cet affichage fonctionne aussi bien avec tests php unit (séparés par des regexp par environnement cette fois)
Ruby : OAuth v1.0a pour optimiser les tests
Lors de tests, il arrive souvent qu'on ait besoin de "faire le ménage" pour retrouver un état comme à l'origine.
Plusieurs stratégies possibles, en fonction des technologies qu'on souhaite utiliser.
Un par un, à la fin
Après chaque scénario, supprimer ce qui a été ajouté, annuler les modifications une par une.
- Avantages :
Facile à mettre en place (on réutilise ce qui a déjà été fait) - Défauts :
Si le scénario plante, on ne remet pas en l'état
Chaque scénario prend un peu plus de temps (jusqu'au double, dans le pire des cas)
Un par un, au début
Avant chaque scénario, remettre les valeurs par défauts pour le test
- Avantages :
Facile à mettre en place (on réutilise ce qui a déjà été fait) - Défauts :
Si la remise à zéro ne marche pas, on ne teste pas
Chaque scénario prend un peu plus de temps (jusqu'au double, dans le pire des cas)
Tous d'un coup, dans une routine à part
Puisqu'on utilise un outil comme jenkins pour organiser tous les tests, on peut ajouter une routine "à part", qui va se connecter sur chaque compte pour effectuer cette remise à zéro.
- Avantages :
Toutes les procédures de remises à zéro sont au même endroit - Défauts :
Un peu plus long à mettre en place
Demande d'ajouter une sécurité pour ne pas la lancer au mauvais moment
Ca prend du temps (mais autant que de le faire un par un)
Optimisation : utilisation d'une API
Dans mon cas, nous disposons aussi d'une API publique (en alpha, elle n'est pas encore ouverte à tout le monde)
- Avantages :
Pas d'interface web, cela devrait aller plus vite
Ajoutera "en passant" des tests sur la public API - Défauts :
Je ne maitrise pas du tout Oauth 1.0a (ça me permettra d'apprendre : tant mieux)
Nous disposons d'un SDK pour faciliter l'utilisation de l'API, en php. Pour des raisons pratiques, je préfère le faire en ruby, le serveur de tests étant déjà configuré pour cela. Je pars donc "de zéro"
Utiliser une API OAuth 1.0a en Ruby
On trouve un peu de documentation pour le faire, et quelques exemples. Quelques remarques sur ces articles :
- La quasi totalité expose le même code d'exemple.
- Rares sont ceux qui signalent la version d'OAuth
- Les exemples se concentrent beaucoup sur "comment se connecter à l'api", et très rarement sur "comment l'utiliser"
Voilà quelques astuces pour utiliser "rapidement" une API OAuth en ruby
Utilisation de gems
Elles facilitent la vie, autant en profiter.require 'oauth' require 'watir-webdriver' require 'json'
Définition de constantes de l'api
OB_API_SERVER = 'http://url_server_api' OB_API_BASE_URL = OB_API_SERVER+'/public/0.1' OB_API_ENDPOINT_REQUEST_TOKEN = '/oauth/request_token' OB_API_ENDPOINT_ACCESS_TOKEN = '/oauth/access_token' OB_API_ENDPOINT_AUTHORIZE = '/oauth/authorize' OB_API_MY_CONSUMER_KEY = '######' OB_API_MY_CONSUMER_SECRET = '######'
Obtenir la connexion à l'API
# create the OAuth consumer
@consumer = OAuth::Consumer.new(
OB_API_MY_CONSUMER_KEY,
OB_API_MY_CONSUMER_SECRET,
{
:oauth_version => '1.0a',
:site => OB_API_SERVER,
:request_token_path => OB_API_ENDPOINT_REQUEST_TOKEN,
:access_token_path => OB_API_ENDPOINT_ACCESS_TOKEN,
:authorize_path => OB_API_ENDPOINT_AUTHORIZE
}
)
# show all debugs in console
# @consumer.http.set_debug_output($stdout)
# get the authorize url
@request_token = @consumer.get_request_token
# Make as if the user authorize the app
# If you make a web app, you should show the link to your user, and let it click it
# browse the authorize url
@browser = Watir::Browser.new
@browser.goto(@request_token.authorize_url())
# connect with account
@browser.text_field(:name => 'email').set("test@test.fr")
@browser.text_field(:name => 'passwd').set("monmotdepasse")
@browser.button(:name => 'loginSubmit').click
# give access
@browser.form.submit
# get verifier token
# browser url contain oauth_verifier_token
oauth_verifier_token = @browser.url.split("oauth_verifier=")[1]
# grant total access
@access_token = @request_token.get_access_token(:oauth_verifier => oauth_verifier_token)
# no more browser needed
@browser.close
Exemples d'utilisation de l'API OAuth
Une fois qu'on est connecté à l'API, on peut l'utiliser. Il faut lire sa documentation, en général assez touffue, pour savoir ce qu'on peut faire (lister / ajouter / modifier / supprimer).
Voici deux exemples "simplifiés" pour mon exemple.
Classique
Afficher les informations sur le blog courant.get_url_info = OB_API_BASE_URL+'/blog/info' current_blog_info = @access_token.get(get_url_info)
Avec une option
Afficher la liste des titres des articles en brouillons.get_lists_content = OB_API_BASE_URL+'/blog/posts/draft?limit=20' content_list = @access_token.get(get_lists_content) # read json results result = JSON.parse(content_list.body) result['response'].each do | content | puts content['title'] end
Conclusions
Ma routine journalière prenait environ 55 minutes. La nouvelle routine, via l'api, dure environ 90 secondes.
J'ai depuis très envie de l'étendre pour ajouter de nouvelles procédures de remises à zéro.
La documentation est primordiale (que ce soit celle de l'API ou celle de OAuth)
Comment organiser les tests sur le long terme
Exécuter une partie des tests
Les scénarios sont taggués pour être lancé par jenkins par la commande :
cucumber --tag @montag
Cela permet de ne lancer qu'une partie des tests. (voir "Tester sur plusieurs navigateurs" pour les détails)
Serveurs
Côté serveur, nous avons 2 serveurs jenkins.
Le principal, une grosse machine debian quadri core, qui exécute jusqu'à 3 jobs en même temps.
Ensuite, un serveur Windows, avec un jenkins "slave".
L'esclave reçoit ses ordres du maître, qui lui demande d’exécuter des jobs particuliers.
Il est sous Windows pour pouvoir les exécuter sur Internet Explorer.
Pour éviter les effets de bords entre les tests sur IE, pas de solution. On vide donc les cookies, le cache, etc à la fermeture d'Internet Explorer.
On ne peut donc pas exécuter les tests pour IE en parallèle sur le même serveur : les sessions se mélangeraient.
Quelques chiffres
Les scenarios sont regroupés en feature, dont le temps d'execution est de maximum 10 minutes.
Dans Jenkins on a 38 "jobs" sur FF (+ 34 sur IE)
Firefox
Chaque jour : 323 scénarios / 2693 step => 3h
IE (1 fois par semaine actuellement, 1 fois par jour bientôt)
Chaque jour : 302 scénarios / 2527 step => 4h 30
Cela représente 227 500 scénarios par an (pour 2 737 heures de tests).
Sans oublier les lancements à la demande de certains jobs.
Comptes utilisateurs
Du côté des scénarios, ils utilisent pour le moment 70 comptes utilisateurs différents (avec des options particulières, etc...)
Un changement prochain de notre offre me fait penser que les tests auront besoin de 100 comptes d'ici 2 à 3 semaines.
Sans oublier de dupliquer tout ça pour nos 2 environnements (test / stable)
Et on ajoute des tests fonctionnels en dehors de ce schéma, pour tester des choses particulière, que ce soit en production sur des points essentiels ou la validité de données particulières.
Et vous, combien vous testez ?
Des tests automatiques avec contenus aléatoires
Si vous avez plusieurs tests qui s’exécutent en même temps sur le même environnement (le serveur de test), il faut veiller à bien tester la "bonne chose".
Prenons un exemple de deux tests exécutés en même temps :
@scenario1
Scenario: Test modif pseudo
Given I connect to my "pseudo" account
When I change my nickname for "pseudo-tmp"
When I publish an article "test pseudo-tmp"
Then my published pseudo is "pseudo-tmp"
@scenario2
Scenario: Pseudo can't be empty when you publish
Given I connect to my "pseudo" account
When I change my nickname for ""
When I publish an article "test pseudo"
Then my published pseudo is "pseudo"
Si les 2 scénarios se terminent "au même moment", nous aurons sur la page de contrôle 2 articles. L'un signé avec "pseudo-tmp", et l'autre avec "pseudo".
Si la vérification vérifie dans tout le contenu de la page des publications et pas seulement le dernier élément, cela pourrait bien se passer.
A un détail près :
- A 10h, le test s’exécute, il fonctionne.
- A 15h, le test s’exécute mais les articles parus à 10h sont peut-être toujours affichés. On aura donc bien un article "test pseudo" sur la page alors qu'un bug sera présent.
Ma solution : ajouter de l'aléatoire dans les tests.
Avant chaque scénario, je crée un token, composé de :
- 2 lettres du navigateur (ff, ie, ch..)
- un nombre aléatoire.
Et je l'affiche en console (bien pratique pour débugguer)
Before do
$token = Token.new
puts "Token for this test : #{$token.value}"
/* je vous fais grace du code pour lancer le navigateur, ... */
End
Ma classe Token :
# Use to got random value
# Useful to post a data with random string but keep the value to check it later
# Author:: Fabrice
class Token
# Create a new token
# Author:: Fabrice
def initialize
@value = "#{ENV['BROWSER']}#{256*256+rand(1024*1024)}"
end
# Get the value of the last token
# Author:: Fabrice
def value
@value
end
end
Ensuite, sans modifier le scénario, on modifie le code des étapes. Lorsqu'on sauve une donnée, on ajoute le token "courant" dans le champ.
title = "#{title} #{$token.value}"
Et côté vérification, on en tient compte également.
def open_article(title, token = false)
if(token)
@browser.link(:text => "#{title} #{$token.value}").click
else
@browser.link(:text => "#{title}").click
end
end
Parfois, on a besoin de pouvoir jouer "sans token" pour des points bien précis : on prévoit alors un paramètre pour s'en passer. (Exemple, pour la saisie d'un email)
Ce genre de solution peut aussi vous éviter des effets de bords si vous publiez sur le même compte des articles avec le même titre. (Ceci, c'est un autre test à part entière)
L'armée ne paie pas toujours ses militaires.
Il y a plusieurs mois, j'avais tweeté "Les bugs, ça coûte cher : Noël sans solde pour des milliers de soldats français"
Source : http://www.lemonde.fr/international/article/2012/12/21/des-milliers-de-soldats-francais-non-payes-a-cause-d-un-bug-informatique_1809606_3210.html
Pour résumer : dans les anciens logiciels de paie des militaires français, il y avait parfois des petites erreurs, des petits bugs, qui étaient corrigés les mois suivants. Mais en 2012, mise à jour complète du logiciel.
Louvois, le logiciel le plus buggué de l'histoire ?
La dernière version du logiciel, surnommée "Louvois" (Logiciel unique à vocation interarmées de la solde) , est tellement remplie de bugs que certains militaires ont de légers problèmes. (Exemples en fin d'article)
Il y a un mois, on pouvait lire dans la presse que les bugs devaient être corrigés pour Noël 2012, mais ne l'étaient pas encore mi février 2013.
Source : http://www.lemagit.fr/technologie/applications/applications-transversales-pgi/2013/02/20/logiciel-de-paie-louvois-la-guerre-de-le-drian-est-loin-detre-gagnee/
On envisagerait donc de revenir à l'ancien logiciel, moins buggué. Mais cela prendrait entre 12 et 14 mois, donc, mi 2014 au mieux.
Une autre source indique que l'armée de l'air paierait déjà ses hommes via un autre logiciel pour éviter les bugs : http://www.marianne.net/blogsecretdefense/Louvois-l-armee-de-Terre-pourrait-revenir-a-l-ancien-systeme-de-paiement-des-soldes_a942.html
Les erreurs occasionnées par Louvois représentent 1 % de la masse salariale du ministère de la Défense, pour près de 120 000 incidents
Et pendant ce temps, dans l'armée de terrain
Saisie sur salaire à un miliaire, pour une somme déjà payée au trésor public par le militaire par ailleurs. (Donc, il est dans le rouge, et paie 2 fois). Temps avant remboursement : plusieurs mois.
Un homme qui doit faire vivre sa famille un mois entier avec 60 euros : http://storify.com/fabrice31/l-armee-mauvais-payeur
Soldes payées avec des mois de retard sur le terrain
Primes prévues mais reportées, payées avec plusieurs mois de retard...
Sur une compagnie de 120 hommes, pour le même mois, déjà plus de 20 cas recensés avec une erreur sur le solde, de 150 à 1 400 €. (La cause serait la prime versée le mois précédent, considérée comme un trop perçu par le logiciel)
Si des militaires veulent poursuivre la liste, n'hésitez pas, je compléterai avec plaisir cette liste de bugs. (un formulaire de contact anonyme est disponible en bas de page)
Et si c'était vous ?
Rappel : les militaires n'ont pas le droit de manifester / faire grève...
Imaginez, si cela ne touchait pas l'armée, mais une société lambda ?
- Une société privée avec un bug aussi important (même une seule fois) qui ne corrige pas dans les jours qui suivent la situation de tous les salariés : que diront les prud'hommes ?
- Une société qui a un bug dans 1% des paies qu'elle verse, Sur une petite PME de 20 personnes, cela fait 1 seule erreur de paie tous les 5 mois. 2.5 erreurs par an.
Pour l'armée, ça représente 3220 personnes par mois. (322 000 emplois en 2007) - Imaginez, si ce mois-ci, votre conjoint(e) reçoit un salaire de 60 € à cause d'une erreur de logiciel, et la suite viendra "plus tard", délai non confirmé. De quoi vous passez vous ? Payer votre loyer, vos crédits ? Les couches de bébé ?
Une page facebook parlait en 2012 du problème : Le paquet de gauloises en colère



