Cela fait plusieurs années que j'assure la qualité d'overblog.com :

  • Tests et validation "manuel" pendant des années,
  • Gestion du support utilisateur par forum ou par mail,
  • Mise en place des tests fonctionnels automatiques,
  • Mise en place des changelog,
  • Rôle de proxy Product Owner lorsque l'équipe est passé à Scrum,
  • A l'occasion, j'ai aussi développé des fonctionnalités sur le projet lui-même,
  • Et plein d'autres petites tâches pour assurer la qualité en général...

En début d'année, lors de mon entretien annuel avec ma hiérarchie, j'ai sous-entendu que je commençais à "m'ennuyer" : je n'avais plus assez de défis à me mettre sous la dent.

J'ai aussi demandé des rendez-vous à quelques reprises avec mon "n+2", pour lui exposer des problèmes d'organisation, et aussi mon ressenti sur le produit et sa qualité. (Je n'aime pas l'appeler mon "n+2", mais c'est plus simple pour en parler ici. Il mérite beaucoup plus que cela : il est à l'écoute, et chaque fois je sors de réunion "prêt à en découdre".)

Comment j'ai changé de travail sans bouger de ma chaise

A la recherche du Graal de l'emploi

A ce moment-là, j'ai mis à jour mon CV, mes informations sur les réseaux, et je suis passé en mode veille "un peu plus active" sur l'emploi dans mon domaine.

J'ai rapidement découvert plusieurs choses :

  • J'ai acquis au sein de ma société une autorité "naturelle" dans le domaine de la Qualité, et des tests.
  • J'ai une autonomie très importante pour faire mon travail, et j'aime ça !
  • Les postes dédiées à la qualité et/ou aux tests ne courent pas les rues
  • Certains postes dans le domaine ne me conviennent pas
  • Se limiter à une région géographique limite encore plus les offres

J'ai du coup pensé à changer de carrière pour rester dans ma région, mais je n'avais pas envie de redevenir développeur "lambda" (et qu'on ne me parle pas de chef de projet). Je me suis même demandé pourquoi je restais dans l'informatique (quand je dis que je ratisse, je ratisse large).

Au printemps, j'allais au travail avec un peu moins d'entrain, et avec le recul, je me suis aperçu que je me faisais des montagnes de certains petits tracas sans importance. Mais hors de question pour moi de partir sans savoir où aller.

Comment j'ai changé de travail sans bouger de ma chaise

Le casse du siècle ?

Et puis, au début de l'été, on m'a fait une proposition intéressante : * Mettre en place des tests automatiques sur des projets web * Travailler en binôme avec quelqu'un déjà en place * Travailler sur 5 ou 6 projets web distincts (mais ayant des parties communes) * Toucher à des domaines que je ne maîtrise pas : faire des tests sur du flash ou des applications mobiles, de beaux défis ! * Accompagner les équipes techniques pour améliorer la Qualité Ce poste paraissait trop beau pour être vrai, mais il était pourtant parfait pour moi. OverBlog fait partie du groupe Ebuzzing depuis plusieurs années. Ebuzzing diffuse un certains nombre de projets. Depuis cet été, j'assure maintenant la qualité de tous ces projets.

Ils vécurent heureux et eurent beaucoup de tests

Ils vécurent heureux et eurent beaucoup d'enfants

Depuis, j'ai un nouveau travail.

  • Je n'ai pas changé de bureau. Je suis toujours assis au même endroit, avec mes habitudes.
  • Mon "n+2" est toujours le même. Pour moi, c'est vraiment une bonne chose : j'ai appris à l'apprécier, et à le respecter depuis longtemps.
  • Je n'ai pas changé de collègues, mais la liste des collègues avec qui je travaille s'est allongée.
  • Si depuis longtemps je codais "propre" et réutilisable sans même avoir besoin de le faire, depuis cet été je le met en pratique. Le temps "perdu" pour cela a "enfin" été rentabilisé.
  • Travailler en binôme est stimulant. Il ne se passe pas une semaine sans qu'une idée de l'un de nous fasse rebondir l'autre pour affronter un problème particulier.
  • Former mon binôme à mes méthodes de travail est intéressant. Il me permet de voir que certains choix ne sont pas forcément pertinents et logiques. Au bout de 4 mois, j'ai déjà repéré plusieurs fois que l'un finissait la phrase de l'autre : juste parfait à mes yeux.
  • Pouvoir chaque jour travailler sur un projet différent est génial : je n'ai plus de routine (les habitudes sont ma hantise)
  • Même si mon autonomie n'est pas aussi importante qu'avant, j'en ai quand même beaucoup. C'est plus que suffisant. (je connais beaucoup de gens qui voudraient avoir la moitié de celle que j'ai)

Keep calm and pick quality

Dans notre outil, nous utilisons le langage twig. Cela permet une grande flexibilité, et d'avoir un moteur déjà bien robuste.

Prenons par exemple l'affichage d'une date avec ce code :

Post.Date|datel(Lang.Get("Default date format"))

Notre outil étant multi langue, et les formats de date changeant avec la langue, nous utilisons une locale. En pratique, il s'agit d'une chaîne de caractères indiquant le format.

On pourrait avoir HH:mm pour l'heure par exemple.

Dans l'analyse du bug du jour, nous avons un signalement de date fausse sur certaines pages. Après vérifications nous trouvons une page datant du 3 janvier 2010, mais qui est affichée comme étant le 3 janvier 2009.

L'enquête se poursuit en vérifiant les dates des autres pages : la quasi totalité des pages affichent une date juste. On finit par regrouper les pages à problèmes suivant le critères : certaines pages de début janvier de certaines années (mais pas toutes).

Le collègue qui cherchait a trouvé le problème.

Default date format = MMMM d Y

Dans la documentation de datel, Y = year of "Week of Year". Il s'agit de l'année durant laquelle le week end du jour en question a eu lieu.

Il s'agit donc d'un bug visible pour les premiers jours de janvier pour lesquels la semaine commençait l'année d'avant. Tordu non ?

Pour la petite histoire, le code corrigé sans bug donne :

Default date format = MMMM d yyyy

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.

Exemple avec les tests fonctionnels

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)

Affichage de résultats cucumber Plugin jenkins affichage de résultats cucumber

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)

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)

Ni d'ajouter l'exécution de ces tests sur chrome.

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 ?