Text Size
Vendredi 18 avril 2014
                        

Logiciels libres

Pour analyser un projet Play framework avec Sonar, je vous propose d'utiliser Apache Ant et Cobertura.

Installation du plugin Cobertura

Le plugin Cobertura va nous permettre d'analyser la couverture de code des tests de notre projet.
Il suffit, pour utiliser Cobertura avec Play!, d'installer le plugin correspondant ; l'analyse s'exécutera automatiquement après le lancement des tests (que ce soit avec play test, play auto-test, ou encore en lançant les classes JUnit). On peut également lancer l'analyse à la main et explorer les résultats via http://localhost:9000/@cobertura lorsque le projet est lancé en mode test (play test).

Pour installer le plugin Cobertura, exécutez la commande :

$ play install cobertura-2.4

puis ajoutez la dépendance à votre projet Play! en ajoutant la ligne suivante dans le fichier conf/dependencies.yml de votre projet :
 - play -> cobertura 2.4

Installation de Sonar

Sonar peut être lancé "out of the box" sur votre machine, il suffit de le télécharger, de le décompresser et d'exécuter le script correspondant à votre OS : http://www.sonarsource.org/downloads/
Pour une installation plus complète : http://docs.codehaus.org/display/SONAR/Install+Sonar#InstallSonar-Installationin4steps

Conflit de port entre Sonar et Play

Vous le remarquerez rapidement, Sonar et Play! écoutent par défaut sur le port 9000. Il est donc bien utile de changer la configuration de l'un ou de l'autre.
Pour changer le port utilisé par votre application Play!, modifiez le fichier conf/application.conf et ajoutez la ligne suivante (avec le port que vous souhaitez) :

http.port=9009

Pour changer le port utilisé par Sonar, modifiez le fichier conf/sonar.properties qui se trouve dans le répertoire d'installation de Sonar, et ajoutez la ligne suivante (avec le port que vous souhaitez) :
sonar.web.port:   9008

Antification du projet Play

Pour utiliser Ant pour lancer votre application, exécutez la commande suivante à la racine de votre projet :

$ play antify

Cela génère un fichier build.xml que l'on complètera ensuite. Vous pouvez alors lancer les commandes habituelles via Ant : ant run, ant test. Pour connaître toutes les cibles Ant, exécutez la commande suivante :
$ ant -p

Pour que les cibles fonctionnent, vous devez avoir défini la variable d'environnement PLAY_PATH (je l'ai fait dans mon fichier ~/.bashrc).

Installation de la tâche sonar-ant

Documentation : http://docs.codehaus.org/display/SONAR/Analyse+with+Ant+Task
Téléchargez la tâche : http://repository.codehaus.org/org/codehaus/sonar-plugins/sonar-ant-task/1.2/sonar-ant-task-1.2.jar
Ensuite vous avez deux possibilités :
- copier ce jar dans ${ANT_HOME\}/lib ainsi la tâche fonctionnera sans configuration supplémentaire :

<taskdef uri="antlib:org.sonar.ant" resource="org/sonar/ant/antlib.xml" />

- sinon, le mettre où vous le souhaitez, il vous faudra alors ajouter la configuration suivante dans le fichier build.xml :
<taskdef uri="antlib:org.sonar.ant" resource="org/sonar/ant/antlib.xml">
 <classpath path="path/to/sonar/ant/task/lib" />
 </taskdef>

J'ai choisi la première solution, sous Ubuntu cela se fait ainsi :
$ sudo mv /home/nephtys/Téléchargements/sonar-ant-task-1.2.jar /usr/share/ant/lib/.
$ sudo chown root:root /usr/share/ant/lib/sonar-ant-task-1.2.jar

Configuration de la cible sonar

Pour pouvoir analyser notre projet Play! dans Sonar, on commence par créer la cible "sonar" dans le fichier build.xml :

<target name="sonar">
</target>

Puis on lui ajoute les ligne de configuration suivantes :
 <property name="sonar.sources" value="app,test" />

pour que Sonar sache où trouver les fichiers source de l'application et des tests
 <property name="sonar.dynamicAnalysis" value="reuseReports" />

pour que Sonar ne réalise pas l'analyse des tests et de la couverture lui-même, mais pour qu'il réutilise les rapports générés par notre application
 <property name="sonar.surefire.reportsPath" value="test-result" />

pour indiquer où sont les rapports générés lors du lancement des tests
 <property name="sonar.cobertura.reportPath" value="test-result/code-coverage/coverage.xml" />

pour indiquer où est le rapport de couverture de code de Cobertura
 <property name="sonar.projectName" value="My Project" />

pour nommer à notre convenance le projet dans Sonar
 <sonar:sonar key="fr.duprey:myproject" version="0.1-SNAPSHOT" xmlns:sonar="antlib:org.sonar.ant" />

pour indiquer à Sonar la clé qui identifie notre projet ; la clé se compose de la version et du couple groupId:artifactId de notre projet.
 <property name="sonar.host.url" value="http://localhost:9008" />

si vous avez changé le port par défaut de Sonar (ou dans le cas où il serait sur une autre machine par exemple)
On obtient alors le fichier build.xml suivant :
<?xml version="1.0" encoding="UTF-8"?>
<project basedir=".">

 <property environment="env" />
 <property name="play.path" value="${env.PLAY_PATH}" />
 <import file="${play.path}/resources/application-build.xml" />

 <taskdef uri="antlib:org.sonar.ant" resource="org/sonar/ant/antlib.xml" />

 <target name="sonar">
 <property name="sonar.sources" value="app,test" />
 <property name="sonar.dynamicAnalysis" value="reuseReports" />
 <property name="sonar.surefire.reportsPath" value="test-result" />
 <property name="sonar.cobertura.reportPath" value="test-result/code-coverage/coverage.xml" />
 <property name="sonar.projectName" value="My Project" />
 <sonar:sonar key="fr.duprey:myproject" version="0.1-SNAPSHOT" xmlns:sonar="antlib:org.sonar.ant" />
 </target>
</project>

Il suffit ensuite de lancer la commande suivante pour analyser le projet (Sonar doit être lancé !):
$ ant sonar

Aller plus loin avec une tâche "tout-en-un"

L'analyse complète (tests, couverture de code, déploiement dans Sonar) de notre projet Play! se fait donc en lançant les commandes :

$ rm -rf test-result/
$ play auto-test
$ ant sonar

Pour automatiser le tout, on pourrait lancer ces trois tâches en une seule cible "qualité" qui pourrait par exemple être utilisée par Hudson/Jenkins dans un soucis d'intégration continue :
<?xml version="1.0" encoding="UTF-8"?>
<project basedir=".">

 <property environment="env" />
 <property name="play.path" value="${env.PLAY_PATH}" />
 <import file="${play.path}/resources/application-build.xml" />

 <taskdef uri="antlib:org.sonar.ant" resource="org/sonar/ant/antlib.xml" />

 <target name="sonar">
 <property name="sonar.sources" value="app,test" />
 <property name="sonar.dynamicAnalysis" value="reuseReports" />
 <property name="sonar.surefire.reportsPath" value="test-result" />
 <property name="sonar.cobertura.reportPath" value="test-result/code-coverage/coverage.xml" />
 <property name="sonar.projectName" value="My Project" />
 <sonar:sonar key="fr.duprey:myproject" version="0.1-SNAPSHOT" xmlns:sonar="antlib:org.sonar.ant" />
 </target>

 <target name="clean-tests-results">
 <delete dir="test-result" />
 </target>
 
 <target name="autotest">
 <exec executable="play">
 <arg value="auto-test" />
 </exec>
 </target>
 
 <target name="quality" depends="clean-tests-results, autotest, sonar" />
 
</project>

Vous remarquerez que j'ai redéfini la cible auto-test alors qu'elle existe déjà dans le fichier Ant de Play! ; en effet, dans mon cas, cette cible ne fonctionne pas (ni la cible precompile).
En lançant :
$ ant quality

Vous lancerez donc vos tests, l'analyse de la couverture de code, et l'analyse de la qualité de votre projet dans Sonar.
Vous n'avez alors plus qu'à aller regarder le résultat ici : http://localhost:9008 (ou http://localhost:9000 si vous n'avez pas modifié le port par défaut de Sonar).

By A Web Design

Logiciels libres - Général

J'ai intégré il y a quelques semaines easyb/Selenium dans un projet Java/Apache Maven pour réaliser des tests d'acceptation. Ayant rencontré quelques écueils, je vous fais profiter des solutions que j'ai pu trouver :)

Qu'est-ce qu'Easyb ?

Easyb est un framework de BDD : Behavior Driven Development. Pour décrire ça simplement, imaginez faire du Test Driven Development en vous focalisant sur la vérification des comportements attendus de votre logiciel, en décrivant les cas de test dans un langage naturel, compréhensible par tous (et notamment les non-développeurs).
Easyb peut donc servir à faire du test unitaire, mais il est également tout indiqué pour les tests d'acceptation (vérification que les exigences représentées par les spécifications du logiciel sont respectées), par exemple dans le cadre de votre sprint Agile, pour vérifier que la user story est finie.
Easyb permet d'écrire des tests facilement et rapidement, grâce à son langage dédié (DSL : Domain-Specific Language) qui autorise des constructions comme shouldBeEqual, shouldBeAn, ensureThrows, isAString, contains, etc. Mais pour moi, ce qui vous fera peut-être l'adopter dans le cadre des tests d'acceptation, c'est sa capacité à être compréhensible pour les développeurs comme pour les chefs de produit ; les stories sont rédigées avec la construction "given... when... then...", les rapports générés sont donc compréhensibles par tous, et le test est de lui-même entièrement documenté. Easyb vous incite à décrire ce que fait votre test précisément.

Intégration

Vous trouverez un exemple d'intégration easyb / java / maven / selenium ici : https://github.com/Nephtys/easyb-sample

Première étape, intégrer easyb via Maven

Il suffit pour cela d'ajouter le plugin maven-easyb-plugin :


<plugin>
 <groupId>org.easyb</groupId> 
 <artifactId>maven-easyb-plugin</artifactId> 
 <version>1.3</version> 
 <executions> 
 <execution> 
 <goals> 
 <goal>test</goal> 
 </goals> 
 </execution> 
 </executions> 
</plugin>

Ensuite, on peut générer les rapports en lançant :


mvn test

pour lancer tous les tests y compris ceux easyb


mvn easyb:test

pour lancer uniquement les tests easyb
On peut également générer un rapport HTML ou XML (par défaut, c'est un rapport TXT), ne lancer que les tests marqués avec un tag spécifique : http://www.easyb.org/maven-easyb-plugin/usage.html

Seconde étape, lancer chaque fichier de test indépendamment dans Eclipse

Il suffit pour cela d'installer le plugin easyb pour Eclipse.
Attention ! Si vous n'avez pas le plugin Groovy installé, installez le plugin Groovy d'abord ! Lors de l'installation du plugin easyb, vous n'êtes pas prévenu... cela m'a valu un Eclipse qui se lance et s'auto-kill en boucle :)
Le plugin easyb s'installe via le site de mise à jour :
Le plugin Groovy s'installe avec le site :
Sélectionner les items :
  • Groovy-Eclipse (Required)
  • m2e Configurator for Groovy-Eclipse (Optional)

Troisième étape, lancer les tests easyb via JUnit

Pour cela :
Récupérer le jar à cet endroit
Si vous voulez pouvoir l'utiliser avec Maven, installez-le dans votre repo local (ou distant si vous en avez la possibilité)


mvn  install:install-file -Dfile=easyb-junit-0.5.3.jar -DgroupId=org.easyb  -DartifactId=easyb-junit -Dversion=0.5.3 -DgeneratePom=true  -Dpackaging=jar

A cause d'incompatibilités de versions, si vous lancez les tests JUnit avec Maven, vous devrez changer la version du plugin easyb pour la version 0.9.7-1.
Puis vous pourrez ajouter la dépendance au fichier pom.xml :



<dependency>
<groupId>org.easyb</groupId>
<artifactId>easyb-junit</artifactId>
<version>0.5.3</version>
<scope>test</scope>
</dependency>

Ce jar ne contient pas les dépendances (donc il n'est pas vraiment adapté), si vous ne souhaitez pas le regénérer, ajoutez la dépendance à easyb en plus dans votre pom.xml :



<dependency>
<groupId>org.easyb</groupId>
<artifactId>easyb</artifactId>
<version>0.9.7</version>
<scope>test</scope>
</dependency>

La classe Launcher suivante vous permettra de lancer les tests easyb dans la vue JUnit :


package fr.duprey.easyb;

import java.io.File;

import org.easyb.junit.EasybSuite;

/**
 * Lauches all easyb stories and specifications with JUnit
 */
public class EasybTestSuiteLauncher extends EasybSuite {

 @Override
 protected File baseDir() {
 return new File("src/test/easyb");
 }

 @Override
 protected String description() {
 return "Easyb Test Suite";
 }

}

Le résultat se présentera ainsi :
Easyb avec JUnit

Quatrième étape, utiliser Selenium dans les tests easyb

Pour cela, ajoutez la dépendance suivante :



<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-server</artifactId>
<version>2.5.0</version>
<scope>test</scope>
</dependency>

Puis, j'ai choisi de créer une story qui proposera le comportement "start selenium" et "stop selenium" aux autres stories, pour factoriser le code :


package fr.duprey.easyb.sample.utils

import org.openqa.selenium.server.SeleniumServer
import com.thoughtworks.selenium.DefaultSelenium

shared_behavior "start selenium", {
 given "selenium is up and running", {
 server = new SeleniumServer();
 server.start();
 selenium = new DefaultSelenium("localhost",
 4444, "*firefox", "http://you.base.url")
 selenium.start()
 }
}

shared_behavior "stop selenium" , {
 then "selenium should be stopped", {
 selenium.stop()
 server.stop()
 }
}

Ainsi, une story utilisant selenium sera codée de cette façon :


package fr.duprey.easyb.sample;

shared_stories "./utils/WithSeleniumBehavior.story"

before "start selenium", {
it_behaves_as "start selenium"
}
after "stop selenium", {
it_behaves_as "stop selenium"
}

scenario "an invalid password has been entered", {

 when "filling out the connexion form with somebody's credentials", {
 selenium.open("/connexion/?lang=fr")
 selenium.type("email", "youremail")
 selenium.type("password", "42")
 }

 and "the submit link has been clicked", {
selenium.click("connexion")
selenium.waitForPageToLoad("2000")
}

 then "the page should display an error message on the password field", {
 passwordFieldErrorSelector = "//form/div/div[text()='Mot de passe']/../div[@class='champs erreur']/span"
 selenium.getText(passwordFieldErrorSelector).shouldBeEqualTo "Mot de passe incorrect"
 }
}

ce qui va donner à l'exécution :


given selenium is up and running
when filling out the connexion form with somebody's credentials
and the submit link has been clicked
then the page should display an error message on the password field
then selenium should be stopped

Attention

  • Pour que le plugin Eclipse, le plugin Maven, ou le plugin JUnit acceptent de lancer vos tests, vous devez suivre une règle simple : l'extension de vos fichiers doit être .story ou .specification (et pas .groovy, bien qu'ils contiennent du Groovy. Le plugin Eclipse reconnaitra les fichiers et utilisera la coloration syntaxique Groovy).
  • Vous ne pouvez pas utiliser toutes ces méthodes en même temps :
    • le plugin JUnit ne supporte pas les versions d'easyb 0.9.8 et supérieures (il existe un patch http://code.google.com/p/easyb-junit/issues/detail?id=7 pour le support de la 0.9.8)
    • les tags ont été introduits dans easyb 0.9.8, donc le flag
      -Deasyb.tags='runme,metoo'
      du plugin Maven ne fonctionnera pas avec les versions antérieures
    • le plugin Maven (tout du moins les versions 0.9.7-1 et 1.3 que j'ai testées) a des problèmes d'encodage, les tests Selenium qui vérifient par exemple des phrases contenant des accents échouent avec le plugin Maven (expected "Connectez-vous à" but was "Connectez-vous �") mais passent avec le plugin Eclipse.
    • le plugin Maven 0.9.7-1 a des problèmes dans la génération du rapport HTML : il n'est généré qu'une fois sur trois en moyenne. J'ai l'impression que c'est mieux avec la version 1.3, et c'est peut-être dû ici aussi à des problèmes d'encodage.
  • si vous choisissez la génération de rapport HTML avec le plugin Maven, précisez le nom du rapport sinon vous obtiendrez l'extension .txt (étrange !).
Pour résumer les combos possibles :
  • maven-easyb-plugin 0.9.7-1 + easyb 0.9.7 + easyb-junit 0.5.3
    • + maven
    • + junit
    • - tags
    • - rapports HTML
  • maven-easyb-plugin 1.3 (pas besoin de dépendance easyb)
    • + maven
    • - junit
    • + tags
    • + rapports HTML

Conclusion sur les possibilités d'intégration

JUnit apporte clairement l'avantage de la visualisation rapide des étapes de la story qui échouent (vert/rouge). Mais il requiert du travail supplémentaire (l'écriture du Launcher) et ne permet pas d'utiliser les dernières versions du plugin Maven et d'easyb (donc on ne profite pas des corrections et des nouvelles fonctionnalités bien utiles comme les tags).
Avec le plugin easyb pour Eclipse, on peut lancer les stories une par une dans Eclipse et voir le résultat dans la console ; même si c'est un résultat "texte" (de plus, il est assez "pollué" si on utilise Selenium) et donc moins lisible que le vert/rouge de JUnit, je trouve cette méthode suffisante et donc je la préfère à l'utilisation d'anciennes versions d'easyb.

A propos des tests d'acceptation

Les tests d'acceptation permettent une meilleure communication entre développeurs, entre les développeurs et les chefs de produit, ils permettent d'automatiser la vérification que le comportement attendu est bien reproduit, (et par la suite, lors des sprints suivants, qu'il n'y a pas de régressions dues aux nouvelles implémentations, à condition de maintenir les tests), ils sont un très bon moyen de vérifier que toute l'équipe partage la même vision de ce qui est attendu du logiciel/de la user story, ou encore de "ce qui est fini" (Done) ; ils permettent de documenter le code : on peut les considérer comme des spécifications exécutables. Mais il faut garder à l'esprit qu'ils ne permettent pas de vérifier l'absence de bug ni la qualité du logiciel si on se contente de tester les cas attendus.
Une discussion intéressante sur ce dernier point : http://www.satisfice.com/blog/archives/638

Lectures

Autres articles intéressants sur l'ATDD et easyb :

By A Web Design

Logiciels libres - Général

Pour produire un mot de passe de type hash SHA1 encodé en base 64, en une ligne de commande (utile également dans un script shell) :


$ echo -ne "$(echo -n "thepassword" | sha1sum | cut -f1 -d" " | sed -e 's/\(.\{2\}\)/\\x\1/g')" | base64
gquHbROHv6/kbMHIou8HTq5Qyx0=

Logiciels libres - Général

Introduction

Ubuntu 11.04 amène une nouveauté assez controversée : Unity, une nouvelle interface de bureau qui a pour but de mieux utiliser l'espace disponible à l'écran.

Personnellement j'apprécie cette nouvelle interface, même si je ne la trouve pas encore tout a fait fluide, et surtout, pas assez configurable. Je trouve la barre de menu globale effectivement bien pensée pour économiser de l'espace à l'écran, et j'apprécie le "launcher", la barre de lancement d'Unity qui se trouve à gauche de l'écran : je suis une habituée des docks (awn par exemple) et celui-ci, bien que peu configurable, me convient pour l'instant ; j'apprécie également qu'il soit à gauche de l'écran, les écrans d'aujourd'hui étant très larges mais pas très hauts, il vaut mieux garder un maximum de place utile en hauteur.

Cependant, j'avoue qu'une barre de lancement qui disparait automatiquement, je trouve ça très peu ergonomique : il faut attendre pour qu'elle s'affiche, on perd du temps car on ne peut prévoir à l'avance où sera l'icône à cliquer vu qu'elle est cachée, et surtout, surtout, elle ne s'affiche pas toujours quand on le souhaite et elle s'affiche souvent quand on ne le souhaite pas : quand je clique sur le bouton Page précédente tout en haut à gauche de Firefox, 1 fois sur 2 je vais trop à gauche et elle s'affiche et m'empêche de cliquer où je le souhaite.

J'ai donc eu envie de la laisser affichée en permanence. Mais là... j'ai eu beau chercher chercher fouiller toutes les options disponibles de mon nouvel Ubuntu, je n'ai pas trouvé où l'option se cachait ; on peut seulement lui dire de s'afficher soit 1) en allant à gauche de l'écran 2) en allant en haut à gauche de l'écran (endroit nommé "bouton Dash", avec le logo Ubuntu).

Sur Internet, j'ai trouvé diverses solutions assez compliquées : about:config qui ne lançait rien du tout, script (que j'ai du corriger) et qui n'avait pas l'effet escompté, etc. J'ai fini par trouver une solution très simple, alors je vous la retransmet des fois que cela vous soit utile :)

Solution

Installer ubuntu-tweak (utilitaire très utile qui permet de configurer Ubuntu plus finement qu'avec ce qui est disponible par défaut dans la distribution) :

sudo add-apt-repository ppa:tualatrix/ppa
sudo apt-get update
sudo apt-get install ubuntu-tweak

Puis lancez ubuntu-tweak, et allez dans l'onglet "Bureau > Configuration de Compiz"

Cochez l'option d'installation et cliquez sur le bouton pour appliquer l'installation.

Vous aurez ainsi un panneau de configuration plus complet. Dans cet onglet toujours, décochez l'option "Make the launcher hide automatically after some time inactive".

Configuration avec Ubuntu tweak

Ainsi la barre de lanceur "Unity launcher" sera constamment affichée.

Logiciels libres - Général

Page 1 sur 4

Début
Précédent
1

Agenda du libre

Le mois dernier Avril 2014 Le mois prochain
L Ma Me J V S D
week 14 1 2 3 4 5 6
week 15 7 8 9 10 11 12 13
week 16 14 15 16 17 18 19 20
week 17 21 22 23 24 25 26 27
week 18 28 29 30
                        

Contact

Laissez moi un message

Profil Viadeo