<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>romain.getBlog( ); &#187; java</title>
	<atom:link href="http://linsolas.free.fr/wordpress/index.php/category/java/feed/" rel="self" type="application/rss+xml" />
	<link>http://linsolas.free.fr/wordpress</link>
	<description></description>
	<lastBuildDate>Wed, 23 Jan 2013 21:29:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.5</generator>
		<item>
		<title>TestNG, votre avis m&#8217;intéresse</title>
		<link>http://linsolas.free.fr/wordpress/index.php/2012/05/testng-votre-avis-minteresse/</link>
		<comments>http://linsolas.free.fr/wordpress/index.php/2012/05/testng-votre-avis-minteresse/#comments</comments>
		<pubDate>Fri, 04 May 2012 11:48:39 +0000</pubDate>
		<dc:creator>Romain</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[tests]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://linsolas.free.fr/wordpress/?p=282</guid>
		<description><![CDATA[Lors du Devoxx France, j&#8217;avais présenté un Quickie (session courte de 15 minutes) sur TestNG, parce que vos tests le valent bien. Les slides sont d&#8217;ailleurs visibles ici.   Le but de cette présentation est de montrer les atouts de la librairie de tests Java TestNG, en particulier face à l&#8217;omniprésent JUnit.   Il faut [...]]]></description>
			<content:encoded><![CDATA[<p>Lors du Devoxx France, j&#8217;avais présenté un Quickie (session courte de 15 minutes) sur <a href="http://devoxx.fr/display/FR12/TestNG%2C+parce+que+vos+tests+le+valent+bien" onclick="pageTracker._trackPageview('/outgoing/devoxx.fr/display/FR12/TestNG_2C+parce+que+vos+tests+le+valent+bien?referer=');">TestNG, parce que vos tests le valent bien</a>. Les slides sont d&#8217;ailleurs visibles <a href="http://www.slideshare.net/linsolas/devoxx-test-ng" onclick="pageTracker._trackPageview('/outgoing/www.slideshare.net/linsolas/devoxx-test-ng?referer=');">ici</a>.<br />
 <br />
Le but de cette présentation est de montrer les atouts de la librairie de tests Java <a href="http://testng.org/doc/index.html" onclick="pageTracker._trackPageview('/outgoing/testng.org/doc/index.html?referer=');">TestNG</a>, en particulier face à l&#8217;omniprésent <a href="https://github.com/KentBeck/junit" onclick="pageTracker._trackPageview('/outgoing/github.com/KentBeck/junit?referer=');">JUnit</a>.<br />
 <br />
Il faut l&#8217;avouer, aujourd&#8217;hui JUnit a réussi à combler certaines de ses lacunes par rapport à TestNG. Je pense par exemple au groupage / catégorisation des tests (JUnit 4.8 a introduit un <code>@Category</code> bancal, mais grandement aidé par Maven Surefire depuis sa version 2.11), aux tests paramétrés (annotation <code>@Parameters</code> de JUnit), etc.<br />
Toutefois, je reste convaincu de l&#8217;intérêt de TestNG sur JUnit. Mais j&#8217;aimerais connaitre ton opinion&#8230;<br />
 <br />
Bref, toi, lectrice, lecteur de mon blog, si tu fais partie d&#8217;une catégorie suivante :<br />
 </p>
<ul>
   
<li>Tu utilises déjà TestNG</li>
<p>   
<li>Tu as utilisé TestNG par le passé</li>
<p>   
<li>Tu aimerais bien utiliser TestNG</li>
<p>   
<li>Tu t&#8217;intéresses à TestNG</li>
</ul>
<p> <br />
alors ton avis m&#8217;intéresse ! Dis-moi quels sont les intérêts que tu lui trouves ? Pourquoi le préfères-tu à JUnit, ou au contraire pourquoi préfères-tu JUnit ? Que lui manque-t&#8217;il ? Bref, dis moi tout !<br />
 <br />
Merci.</p>
]]></content:encoded>
			<wfw:commentRss>http://linsolas.free.fr/wordpress/index.php/2012/05/testng-votre-avis-minteresse/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Chouchoutez votre JavaScript dans un projet web</title>
		<link>http://linsolas.free.fr/wordpress/index.php/2012/05/chouchoutez-votre-javascript-dans-un-projet-web/</link>
		<comments>http://linsolas.free.fr/wordpress/index.php/2012/05/chouchoutez-votre-javascript-dans-un-projet-web/#comments</comments>
		<pubDate>Thu, 03 May 2012 22:06:30 +0000</pubDate>
		<dc:creator>Romain</dc:creator>
				<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[sonar]]></category>
		<category><![CDATA[tests]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://linsolas.free.fr/wordpress/?p=277</guid>
		<description><![CDATA[Voilà, c&#8217;est fait ! Vous êtes venus à Devoxx France, vous avez assisté à ma présentation (ou alors vous avez juste lu mon post sur le sujet), et donc vous voulez désormais chouchouter votre code JavaScript. Pour démarrer sur le sujet, vous avez suivi les étapes écrites sur mon post, comme je l&#8217;ai fait lors [...]]]></description>
			<content:encoded><![CDATA[<p>Voilà, c&#8217;est fait ! Vous êtes venus à Devoxx France, vous avez assisté à ma présentation (ou alors vous avez juste lu mon <a href="http://linsolas.free.fr/wordpress/index.php/2012/04/chouchoutez-votre-code-javascript">post sur le sujet</a>), et donc vous voulez désormais <strong>chouchouter votre code JavaScript</strong>.</p>
<p>Pour démarrer sur le sujet, vous avez suivi les étapes écrites sur mon post, comme je l&#8217;ai fait lors de ma présentation. C&#8217;est bien joli tout ça, mais dans la vraie vie réelle, vous n&#8217;avez pas un module Maven dédié au code JavaScript. Votre code JavaScript est (bêtement) dans votre application web ! Du coup, vous vous posez des questions sur la façon de procéder, en particulier concernant les analyses Sonar&#8230;</p>
<p>Allez zou, suivez le guide !</p>
<p><span id="more-277"></span></p>
<h2>Zou, créons un projet</h2>
<p>Lors de ma présentation, j&#8217;ai utilisé l&#8217;archetype Maven <code>de.akquinet.javascript.archetypes:javascript-quickstart</code>, qui crée un squelette d&#8217;application contenant juste du JavaScript.<br />
Cette fois-ci, on va partir d&#8217;un projet web classique dans lequel on incluera notre code JavaScript. Donc quelque chose de plus proche que ce que vous avez sur votre projet !</p>
<p>Je pars donc avec l&#8217;archetype <code>org.codehaus.mojo.archetypes:webapp-javaee6</code> pour avoir un squelette d&#8217;application web. Il s&#8217;agit là de votre propre projet web&#8230; De mon côté, j&#8217;y ajoute une petite classe Java, ainsi qu&#8217;une class de test JUnit pour le fun.</p>
<p>Désormais, on peut lancer une première analyse Sonar, avec la commande <code>mvn clean install sonar:sonar</code>.</p>
<div id="attachment_272" class="wp-caption center" style="width: 750px"><a href="http://linsolas.free.fr/wordpress/wp-content/uploads/chouchoutage-1.png"><img src="http://linsolas.free.fr/wordpress/wp-content/uploads/chouchoutage-1.png" alt="" title="chouchoutage-1" width="740" height="455" class="size-full wp-image-272" /></a><p class="wp-caption-text">Jusqu'ici, tout va bien !</p></div>
<p>Maintenant, je rajoute mon code JavaScript (les fichiers <code>underscore.js</code> et <code>undescore-test.js</code>). Je les positionne respectivement dans les répertoires <code>src/main/javascript</code> et <code>src/test/javascript</code>. Il est possible d&#8217;adapter ces répertoires, bien entendu !<br />
On ajoute le fichier de configuration de <code>jsTestDriver.conf</code> qui va nous permettre de lancer nos tests JavaScript de Jasmine. On ajoute aussi dans un coin (le répertoire <code>lib/</code> disons) :</p>
<ul>
<li>le fichier <code>jasmine.js</code> ;</li>
<li>le fichier <code>jasmineAdapter.js</code> (pour lancer les tests JavaScript écrits en Jasmine avec js-test-driver) ;</li>
<li>la librairie <code>coverage-1.3.4.b.jar</code>, qui est le plugin de calcul de couverture du code JavaScript pour js-test-driver.</li>
</ul>
<p>Au final, la structure de mon projet a la tête suivante :</p>
<pre class="brush: plain;">
chouchoutage (oui, c'est le nom pourri de mon projet)
  + pom.xml
  ` src
      + lib
      |   ` coverage-1.3.4.b.jar
      |   ` jasmine.js
      |   ` jasmineAdapter.js
      + main
      |   + java
      |   |   ` ze-code-java
      |   ` javascript
      |       ` underscore.js
      + test
      |   + java
      |   |   ` test-unitaires
      |   ` javascript
      |       ` underscore-test.js
      ` webapp
          ` toute-la-partie-web
</pre>
<p>Si vous souhaitez plus d&#8217;informations sur cette étape (comme le contenu du fichier <code>jsTestDriver.conf</code> par exemple), allez jeter un oeil sur <a href="http://linsolas.free.fr/wordpress/index.php/2012/04/chouchoutez-votre-code-javascript">mon post décrivant ma session Devoxx</a>.</p>
<p>Voilà, on arrive à quelque chose qui ressemble en gros à votre projet. Maintenant, on va voir comment on va pouvoir exécuter nos codes JavaScript, et en faire l&#8217;analyse Sonar.</p>
<h2>Ne tombons pas dans les poms !</h2>
<p>Attaquons nous au problème principal : la modification du pom. Nous allons d&#8217;abord l&#8217;adapter pour exécuter nos tests JavaScript. Nous verrons ensuite pour l&#8217;analyse Sonar&#8230;</p>
<p>Ajoutons d&#8217;abord la dépendance suivante :</p>
<pre class="brush: xml;">
    &lt;dependency&gt;
        &lt;groupId&gt;com.googlecode.jstd-maven-plugin&lt;/groupId&gt;
        &lt;artifactId&gt;jstd-maven-plugin&lt;/artifactId&gt;
        &lt;version&gt;1.3.2.5&lt;/version&gt;
        &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
</pre>
<p>On ajoute ensuite le plugin de <code>jstd-maven-plugin</code> :</p>
<pre class="brush: xml;">
    &lt;plugin&gt;
        &lt;groupId&gt;com.googlecode.jstd-maven-plugin&lt;/groupId&gt;
        &lt;artifactId&gt;jstd-maven-plugin&lt;/artifactId&gt;
        &lt;version&gt;1.3.2.5&lt;/version&gt;
        &lt;configuration&gt;
            &lt;port&gt;9876&lt;/port&gt;
            &lt;!-- A adapter ! --&gt;
            &lt;browser&gt;/Applications/Firefox.app/Contents/MacOS/firefox-bin&lt;/browser&gt;
            &lt;tests&gt;all&lt;/tests&gt;
            &lt;config&gt;jsTestDriver.conf&lt;/config&gt;
            &lt;testOutput&gt;target/jstestdriver&lt;/testOutput&gt;
        &lt;/configuration&gt;
        &lt;executions&gt;
            &lt;execution&gt;
                &lt;id&gt;run-tests&lt;/id&gt;
                &lt;goals&gt;
                    &lt;goal&gt;test&lt;/goal&gt;
                &lt;/goals&gt;
            &lt;/execution&gt;
        &lt;/executions&gt;
    &lt;/plugin&gt;
</pre>
<p>Dernier point, nous ajoutons le repository contenant les plugins sus-cités :</p>
<pre class="brush: xml;">
    &lt;repositories&gt;
          &lt;repository&gt;
              &lt;id&gt;jstd-maven-plugin google code repo&lt;/id&gt;
              &lt;url&gt;http://jstd-maven-plugin.googlecode.com/svn/maven2&lt;/url&gt;
          &lt;/repository&gt;
    &lt;/repositories&gt;
    &lt;pluginRepositories&gt;
          &lt;pluginRepository&gt;
              &lt;id&gt;jstd-maven-plugin google code repo&lt;/id&gt;
              &lt;url&gt;http://jstd-maven-plugin.googlecode.com/svn/maven2&lt;/url&gt;
          &lt;/pluginRepository&gt;
    &lt;/pluginRepositories&gt;
</pre>
<p>Voilà, nous pouvons vérifier si cela fonctionne. La commande <code>mvn clean install</code> va nous le dire :</p>
<pre class="brush: plain;">
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running fr.linsolas.WorldTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.053 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] --- jstd-maven-plugin:1.3.2.5:test (run-tests) @ chouchoutage ---

-------------------------------------------
 J S  T E S T  D R I V E R
-------------------------------------------

Firefox: Runner reset.
................
Total 16 tests (Passed: 16; Fails: 0; Errors: 0) (10,00 ms)
  Firefox 9.0.1 Mac OS: Run 16 tests (Passed: 16; Fails: 0; Errors 0) (10,00 ms)
</pre>
<p>C&#8217;est plutôt une bonne nouvelle ça ! Surefire a lancé mon test JUnit (<code>fr.linsolas.WorldTest</code>), puis, dans un second temps, a exécuté les tests de js-test-driver.</p>
<h2>Plongeons dans l&#8217;analyse Sonar</h2>
<p>Et bien voilà, il ne nous reste plus qu&#8217;à exécuter une analyse Sonar et le tour est joué&#8230; Mais ce n&#8217;est pas si simple en fait !<br />
Sonar permet bien d&#8217;analyser un projet Java, il permet d&#8217;analyser également un projet JavaScript, mais hélas pas en même temps !<br />
Nous allons devoir donc lancer <strong>deux analyses Sonar</strong> pour arriver à nos fins.</p>
<p>Etant donné que nous ne voulons pouvoir lancer avec le même pom.xml l&#8217;analyse Sonar pour le code Java et l&#8217;analyse Sonar pour le code JavaScript, nous allons créer un profil Maven qui sera dédié à l&#8217;analyse JavaScript :</p>
<pre class="brush: xml;">
    &lt;profiles&gt;
        &lt;profile&gt;
            &lt;id&gt;js&lt;/id&gt;
            &lt;properties&gt;
                &lt;sonar.language&gt;js&lt;/sonar.language&gt;
                &lt;sonar.dynamicAnalysis&gt;reuseReports&lt;/sonar.dynamicAnalysis&gt;
            &lt;/properties&gt;
        &lt;/profile&gt;
    &lt;/profiles&gt;
</pre>
<p>Voyons voir si cela fonctionne. Lançons une première analyse avec <code>mvn clean install sonar:sonar</code>. En exécutant cette commande, l&#8217;analyse Sonar ne montre aucune différence avec celle réalisée plus tôt. Normal, me direz-vous, on reste sur l&#8217;analyse Java.<br />
Lançant maintenant la même commande, mais en activant le profile <strong>js</strong> : <code>mvn -Pjs clean install sonar:sonar</code>. Le résultat n&#8217;est pas celui attendu :</p>
<div id="attachment_273" class="wp-caption center" style="width: 766px"><a href="http://linsolas.free.fr/wordpress/wp-content/uploads/chouchoutage-2.png"><img src="http://linsolas.free.fr/wordpress/wp-content/uploads/chouchoutage-2.png" alt="" title="chouchoutage-2" width="756" height="233" class="size-full wp-image-273" /></a><p class="wp-caption-text">Ooooups</p></div>
<p>Houlà, mais on a tout cassé ! On n&#8217;obtient plus aucun chiffre, ni rien <img src='http://linsolas.free.fr/wordpress/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />  Le problème vient simplement du fait que le plugin JavaScript pour Sonar va chercher les sources dans le répertoire <code>src/main/java</code> au lieu de <code>src/main/javascript</code>.<br />
Il faut donc lui spécifier ce nouveau répertoire. On va donc spécifier un <code>sourceDirectory</code> dans notre profile <strong>js</strong>. Du moins on aimerait bien, car hélas Maven n&#8217;autorise pas que l&#8217;on redéfinisse ce répertoire dans un profil ! C&#8217;est étrange, mais c&#8217;est comme ça. Enfin pas tant que ça, car Maven &#8211; par défaut &#8211; n&#8217;accepte qu&#8217;un seul chemin de sources. Comme plusieurs profiles peuvent être actifs en même temps, on pourrait bidouiller les profiles pour avoir ainsi plusieurs répertoires de sources. On s&#8217;égare un peu là&#8230;<br />
Nous pourrions passer par le plugin <a href="http://mojo.codehaus.org/build-helper-maven-plugin/" onclick="pageTracker._trackPageview('/outgoing/mojo.codehaus.org/build-helper-maven-plugin/?referer=');">build-helper</a> qui permet de spécifier plusieurs répertoires de sources. Je n&#8217;en ferais rien, je vais &laquo;&nbsp;simplement&nbsp;&raquo; fourvoyer Maven en jouant avec les propriétés :</p>
<pre class="brush: xml;">
    &lt;properties&gt;
        &lt;source.dir&gt;src/main/java&lt;/source.dir&gt;
        &lt;test.source.dir&gt;src/test/java&lt;/test.source.dir&gt;
    &lt;/properties&gt;

    &lt;build&gt;
        &lt;sourceDirectory&gt;${source.dir}&lt;/sourceDirectory&gt;
        &lt;testSourceDirectory&gt;${test.source.dir}&lt;/testSourceDirectory&gt;
        ...
    &lt;/build&gt;

    &lt;profiles&gt;
        &lt;profile&gt;
            &lt;id&gt;js&lt;/id&gt;
            &lt;properties&gt;
                &lt;source.dir&gt;src/main/javascript&lt;/source.dir&gt;
                &lt;test.source.dir&gt;src/test/javascript&lt;/test.source.dir&gt;
                ...
</pre>
<p>Voilà, Maven n&#8217;y voit que du feu, et moi j&#8217;ai réussi à me débrouiller (à bidouiller disons plutôt).</p>
<p>Alors, que donne l&#8217;analyse Sonar maintenant ?</p>
<div id="attachment_274" class="wp-caption center" style="width: 753px"><a href="http://linsolas.free.fr/wordpress/wp-content/uploads/chouchoutage-3.png"><img src="http://linsolas.free.fr/wordpress/wp-content/uploads/chouchoutage-3.png" alt="" title="chouchoutage-3" width="743" height="454" class="size-full wp-image-274" /></a><p class="wp-caption-text">Voilà qui est mieux !</p></div>
<p>OUI ! Enfin, nous réussissons à obtenir notre belle analyse du code JavaScript par Sonar !</p>
<p>Et voilà, c&#8217;est fini.<br />
Vraiment ? Non !<br />
Un dernier souci se pose : si je lance l&#8217;analyse Java, j&#8217;ai un beau rapport Sonar. Mais dès que je lance l&#8217;analyse JavaScript, mon rapport JavaScript efface celui de Java !<br />
Il faut donc trouver un moyen de faire cohabiter les deux. Je propose simplement de profiter de l&#8217;option <code>sonar.branch</code> pour différencier les deux projets. On ajoute donc dans le profil <strong>js</strong> :</p>
<pre class="brush: xml;">
    &lt;profiles&gt;
        &lt;profile&gt;
            &lt;id&gt;js&lt;/id&gt;
            &lt;properties&gt;
                &lt;sonar.branch&gt;javascript&lt;/sonar.branch&gt;
                ...
</pre>
<p>Cette fois-ci, on relance les deux analyses : <code>mvn clean install sonar:sonar</code> puis <code>mvn -Pjs clean install sonar:sonar</code>.<br />
Une fois les deux commandes terminées, nous nous retrouvons avec non plus un mais deux projets Sonar :</p>
<div id="attachment_275" class="wp-caption center" style="width: 627px"><a href="http://linsolas.free.fr/wordpress/wp-content/uploads/chouchoutage-4.png"><img src="http://linsolas.free.fr/wordpress/wp-content/uploads/chouchoutage-4.png" alt="" title="chouchoutage-4" width="617" height="78" class="size-full wp-image-275" /></a><p class="wp-caption-text">Les deux font la paire</p></div>
<p>Chacun de ces projets est adapté à son langage, le premier pour Java, le second pour JavaScript.</p>
<p>Et voilà, c&#8217;est fini.<br />
Vraiment ? Cette fois, oui <img src='http://linsolas.free.fr/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>N&#8217;hésitez pas à faire part, dans les commentaires, de vos propres expériences, ou propositions d&#8217;améliorations !</p>
<a href="javascript:toggleStartStop();PicLensLite.start({feedUrl:'http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/mrss.php?id=277'});">Start Slide Show with PicLens Lite <img src="http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/PicLensButton.png" alt="PicLens" width="16" height="12" border="0" align="top"></a>]]></content:encoded>
			<wfw:commentRss>http://linsolas.free.fr/wordpress/index.php/2012/05/chouchoutez-votre-javascript-dans-un-projet-web/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Jouons avec les Entités de Play!</title>
		<link>http://linsolas.free.fr/wordpress/index.php/2011/08/jouons-avec-les-entites-de-play/</link>
		<comments>http://linsolas.free.fr/wordpress/index.php/2011/08/jouons-avec-les-entites-de-play/#comments</comments>
		<pubDate>Thu, 04 Aug 2011 23:09:40 +0000</pubDate>
		<dc:creator>Romain</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[play]]></category>

		<guid isPermaLink="false">http://linsolas.free.fr/wordpress/?p=165</guid>
		<description><![CDATA[J&#8217;avais évoqué il y a quelques temps déjà Play!, et j&#8217;avais même traduit le tutoriel officiel en français montrant les capacités de ce framework. Ayant eu l&#8217;occasion de me remettre sur Play! ces derniers jours, je ne peux m&#8217;empêcher de vous faire partager le plaisir que j&#8217;ai eu à l&#8217;utiliser en vous parlant d&#8217;un aspect [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://linsolas.free.fr/wordpress/index.php/2010/01/jouons/">J&#8217;avais évoqué</a> il y a quelques temps déjà <a href="http://www.playframework.org/" onclick="pageTracker._trackPageview('/outgoing/www.playframework.org/?referer=');">Play!</a>, et j&#8217;avais même traduit le <a href="http://linsolas.developpez.com/articles/java/play/guide/" onclick="pageTracker._trackPageview('/outgoing/linsolas.developpez.com/articles/java/play/guide/?referer=');">tutoriel officiel en français</a> montrant les capacités de ce framework.</p>
<p>Ayant eu l&#8217;occasion de me remettre sur Play! ces derniers jours, je ne peux m&#8217;empêcher de vous faire partager le plaisir que j&#8217;ai eu à l&#8217;utiliser en vous parlant d&#8217;un aspect sympathique de ce framework : la gestion des entités.</p>
<p><span id="more-165"></span></p>
<p>Si vous avez déjà eu l&#8217;occasion de vous faire la main sur Play!, vous ne devriez rien apprendre ici. Il s&#8217;agit surtout de donner envie à ceux qui hésitent à se lancer dans l&#8217;aventure Play!.</p>
<h2>L&#8217;entité User</h2>
<p>Commençons par écrire notre entité, que nous appellerons <code>User</code>. Voici le code :</p>
<pre class="brush: java;">
package models;

import javax.persistence.Entity;
import play.db.jpa.Model;

@Entity
public class User extends Model {

    public String name;
    public String email;
    public boolean isAdmin;

    public User() {
    }

    public User(String name, String email, boolean isAdmin) {
        this.name = name;
        this.email = email;
        this.isAdmin = isAdmin;
    }

}
</pre>
<p>Nous notons déjà deux choses importantes :</p>
<ul>
<li>Les propriétés de notre entité sont publiques, et nous ne polluons plus notre classe avec des getters et setters (en attendant les <code>property</code> de Java 8 <img src='http://linsolas.free.fr/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ).</li>
<li>L&#8217;entité étend la classe <code>play.db.jpa.Model</code>. C&#8217;est ce point que nous allons voir en détail juste après.</li>
</ul>
<h2>La super-classe Model</h2>
<p>Cette super-classe <a href="http://www.playframework.org/documentation/api/1.2.2/play/db/jpa/Model.html" onclick="pageTracker._trackPageview('/outgoing/www.playframework.org/documentation/api/1.2.2/play/db/jpa/Model.html?referer=');">Model</a> (et ses parents) vont nous simplifier grandement la vie, car elle nous évitera l&#8217;écriture d&#8217;un DAO. En effet, nous disposons, simplement grâce à notre entité, des principales méthodes de CRUD (<i>Create, Read, Update, Delete</i>):</p>
<ul>
<li><code>count()</code> pour compter le nombre d&#8217;entités, en fournissant éventuellement des paramètres pour affiner la requête ;</li>
<li><code>save()</code> pour sauver notre entité ;</code></li>
</ul>
<p>Voyons quelques exemples basiques avec un test unitaire :</p>
<pre class="brush: java;">
public class UserTest extends UnitTest {

    @Before
    public void clean() {
        Fixtures.deleteDatabase();
    }

    @Test
    public void testAddition() {
        assertEquals(0, User.count());
        new User(&quot;romain linsolas&quot;, &quot;romain@example.com&quot;, true).save();
        assertEquals(1, User.count());
    }

}
</pre>
<p>On notera que nous nettoyons la base de données en mémoire avant chaque test, afin de ne pas fausser nos résultats. De plus, notre classe JUnit étendant la classe <code>play.test.UnitTest</code> afin de profiter de l'environnement de Play! : création de la base de données en mémoire et la structure des tables, par exemple.</p>
<pre class="brush: java;">
    private void insertUsers() {
        new User(&quot;romain linsolas&quot;, &quot;admin@example.com&quot;, true).save();
        new User(&quot;romain linsolas&quot;, &quot;romain@example.com&quot;, false).save();
        new User(&quot;bob l'eponge&quot;, &quot;bob.leponge@example.com&quot;, false).save();
        new User(&quot;romain gary&quot;, &quot;romain.gary@example.com&quot;, false).save();
    }

    @Test
    public void testFindAll() {
        insertUsers();
        assertEquals(4, User.findAll().size());
    }

    @Test
    public void testFindOneArg() {
        insertUsers();
        List&lt;User&gt; list = User.find(&quot;byName&quot;, &quot;romain linsolas&quot;).fetch();
        assertEquals(2, list.size());
        assertEquals(&quot;romain linsolas&quot;, list.get(0).name);
    }

    @Test
    public void testFindTwoArgs() {
        insertUsers();
        List&lt;User&gt; list = User.find(&quot;byNameAndIsAdmin&quot;, &quot;romain linsolas&quot;, true).fetch();
        assertEquals(1, list.size());
        assertTrue(list.get(0).isAdmin);
    }
</pre>
<p>Dans le code précédent, nous insérons quatre utilisateurs, et nous vérifions que la méthode <code>findAll()</code> nous retourne le nombre correct d'éléments. Nous faisons également une autre vérification, où nous recherchons tous les utilisateurs selon la valeur d'une propriété, ici <code>name</code>. Le dernier test permet de montrer une utilisation un peu plus poussée de la méthode <code>find("…")</code>, où nous cherchons tous les utilisateurs ayant un nom donné et dont l'attribut <code>isAdmin</code> vaut <code>true</code>.</p>
<p>Nous pouvons encore améliorer les choses en fournissant encore plus de détails sur la recherche, par exemple comme ceci :</p>
<pre class="brush: java;">
    @Test
    public void testFindAndOrder() {
        insertUsers();
        List&lt;User&gt; list = User.find(&quot;name = ? order by email desc&quot;, &quot;romain linsolas&quot;).fetch();
        assertEquals(2, list.size());
        assertFalse(list.get(0).isAdmin);
    }
</pre>
<p>où nous cherchons les utilisateurs selon un nom donné, puis en les triant selon l'adresse mail. Nous aurions pu encore corsé les choses en mettant en place des jointures avec d'autres entités...</p>
<p>Bien entendu, cette fonctionnalité ne marche pas seulement avec les méthodes de comptage ou de recherche, on pourra l'utiliser avec la méthode <code>delete()</code> :</p>
<pre class="brush: java;">
    @Test
    public void testDelete() {
        insertUsers();
        User.delete(&quot;name = ?&quot;, &quot;romain linsolas&quot;);
        assertEquals(2, User.count());
    }
</pre>
<p>Ce ne sont là que quelques possibilités, la classe <code>Model</code> offre d'autres fonctionnalités permettant les opérations de <i>CRUD</i>.</p>
<h2>Conclusion</h2>
<p>Au final, il n'y rien de révolutionnaire ici, mais que de temps gagné grâce à ces méthodes si utiles ! C'est sans doute ça la force première de Play! : nous offrir un retour rafraichissant à la <b>simplicité</b>. Et ça, c'est bon !</p>
<p>Pour aller plus loin :</p>
<ul>
<li><a href="http://www.playframework.org/" onclick="pageTracker._trackPageview('/outgoing/www.playframework.org/?referer=');">Site de Play!</a></li>
<li><a href="http://linsolas.developpez.com/articles/java/play/guide/" onclick="pageTracker._trackPageview('/outgoing/linsolas.developpez.com/articles/java/play/guide/?referer=');">Tutoriel que j'ai traduit en français sur Play!</a></li>
<li><a href="http://www.playframework.org/documentation/1.2.2/jpa" onclick="pageTracker._trackPageview('/outgoing/www.playframework.org/documentation/1.2.2/jpa?referer=');">Les entités JPA de Play!</a></li>
</ul>
<a href="javascript:toggleStartStop();PicLensLite.start({feedUrl:'http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/mrss.php?id=165'});">Start Slide Show with PicLens Lite <img src="http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/PicLensButton.png" alt="PicLens" width="16" height="12" border="0" align="top"></a>]]></content:encoded>
			<wfw:commentRss>http://linsolas.free.fr/wordpress/index.php/2011/08/jouons-avec-les-entites-de-play/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Calculer sa couverture de code par les tests d&#8217;intégration</title>
		<link>http://linsolas.free.fr/wordpress/index.php/2011/07/calculer-sa-couverture-de-code-par-les-tests-dintegration/</link>
		<comments>http://linsolas.free.fr/wordpress/index.php/2011/07/calculer-sa-couverture-de-code-par-les-tests-dintegration/#comments</comments>
		<pubDate>Fri, 08 Jul 2011 08:07:20 +0000</pubDate>
		<dc:creator>Romain</dc:creator>
				<category><![CDATA[article]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[sonar]]></category>
		<category><![CDATA[tests]]></category>

		<guid isPermaLink="false">http://linsolas.free.fr/wordpress/?p=159</guid>
		<description><![CDATA[Nous allons voir ici comment, grâce à Sonar, Maven et JaCoCo nous pouvons obtenir la couverture de code par des tests d&#8217;intégration. Contexte Dans mon exemple, je me baserais sur les outils suivants : Sonar 2.8, Maven 2.2.1, Java 1.6. Au sein de l&#8217;un de mes projets, je dispose de quelques rares tests unitaires, qui [...]]]></description>
			<content:encoded><![CDATA[<p>Nous allons voir ici comment, grâce à Sonar, Maven et JaCoCo nous pouvons obtenir la couverture de code par des tests d&#8217;intégration.</p>
<p><span id="more-159"></span></p>
<h2>Contexte</h2>
<p>Dans mon exemple, je me baserais sur les outils suivants : <a href="http://www.sonarsource.org/" onclick="pageTracker._trackPageview('/outgoing/www.sonarsource.org/?referer=');">Sonar 2.8</a>, <a href="http://maven.apache.org" onclick="pageTracker._trackPageview('/outgoing/maven.apache.org?referer=');">Maven 2.2.1</a>, Java 1.6.</p>
<p>Au sein de l&#8217;un de mes projets, je dispose de quelques rares tests unitaires, qui couvre environ 7% de l&#8217;application. C&#8217;est peu. Très peu. Trop peu même.<br />
Mais nous avons également des tests d&#8217;intégration.<br />
En gros, ces tests d&#8217;intégration vont exécuter un jeu d&#8217;environ 300 fichiers d&#8217;entrée, qui seront ensuite analysés par mon application.</p>
<p>Mon but est donc de connaître, en plus de ma couverture de test par les tests JUnit, la couverture du code exécuté par mes tests d&#8217;intégration.</p>
<p>La structure de mon projet ressemble en gros à ceci :</p>
<pre class="brush: plain;">
mon-projet
  +- pom.xml (ce pom-là n'est qu'un pom d'aggrégation)
  +- parent
  |   +- pom.xml (c'est le vrai parent de tous les autres modules)
  +- module-1
  |   +- pom.xml
  +- module-2
  |   +- pom.xml
  +- ...
  +- module-tests
      +- pom.xml
      +- src/test/java/
          +- foo/bar/IntegrationTestsRunner.java
</pre>
<p><i>module-tests</i> est un module ne contenant que quelques classes de tests, en particulier <code>IntegrationTestsRunner.java</code> dont le but est d&#8217;aller lire mes fichiers de tests, et les exécuter.</p>
<p>Afin de ne pas lancer ces tests d&#8217;intégration à chaque build, nous définissons un profil Maven dans le <code>pom.xml</code> de <i>module-tests</i>, comme suit :</p>
<pre class="brush: xml;">
    &lt;profiles&gt;
        &lt;profile&gt;
            &lt;id&gt;run-it&lt;/id&gt;
            &lt;activation&gt;
                &lt;property&gt;
                    &lt;name&gt;runIT&lt;/name&gt;
                    &lt;value&gt;true&lt;/value&gt;
                &lt;/property&gt;
            &lt;/activation&gt;
            &lt;build&gt;
                &lt;plugins&gt;
                    &lt;plugin&gt;
                        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                        &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
                        &lt;configuration&gt;
                            &lt;includes&gt;
                                &lt;include&gt;**/IntegrationTestRunner.java&lt;/include&gt;
                            &lt;/includes&gt;
                        &lt;/configuration&gt;
                    &lt;/plugin&gt;
                &lt;/plugins&gt;
            &lt;/build&gt;
        &lt;/profile&gt;
    &lt;/profiles&gt;
</pre>
<p>Ce profil sera activé soit en ajoutant <code>-DrunIT=true</code> soit <code>-Prun-it</code> dans la ligne de commande Maven.</p>
<p>Avec une méthode &laquo;&nbsp;traditionnelle&nbsp;&raquo;, c&#8217;est-à-dire l&#8217;exécution de tests unitaires via Surefire, aucune couverture de code ne sera détectée, car le code exécuté par les tests d&#8217;intégration l&#8217;est sur les autres modules du projet. Or Cobertura ne va instrumentaliser que les classes du module courant et non les dépendances (i.e. <i>module-1</i>, <i>module-2</i>, etc.).</p>
<h2>Mise en place de JaCoCo</h2>
<p>Pour résoudre mon problème, je vais faire appel à <a href="http://www.eclemma.org/jacoco/" onclick="pageTracker._trackPageview('/outgoing/www.eclemma.org/jacoco/?referer=');">JaCoCo</a>, un outil de couverture de test plus performant que Cobertura. Son principal avantage est de pouvoir instrumentaliser les classes au runtime. Dans mon cas présent, JaCoCo va donc pouvoir vérifier la couverture du code sur les différents modules au moment où l&#8217;on exécute <i>module-tests</i>.</p>
<p>Avant toute chose, il va nous falloir configurer un peu notre environnement :</p>
<ul>
<li>Installer le plugin <a href="http://docs.codehaus.org/display/SONAR/JaCoCo+Plugin" onclick="pageTracker._trackPageview('/outgoing/docs.codehaus.org/display/SONAR/JaCoCo+Plugin?referer=');">JaCoCo pour Sonar</a> (à copier dans le répertoire <i>extensions/plugins</i> de son installation Sonar).</li>
<li>Une fois Sonar redémarré, penser à ajouter dans le dashboard le widget <i>IT Coverage Widget</i> (il faudra sans doute pour cela être connecté en tant qu&#8217;administrateur).</li>
<li>Télécharger l&#8217;<a href="http://www.eclemma.org/jacoco/trunk/doc/agent.html" onclick="pageTracker._trackPageview('/outgoing/www.eclemma.org/jacoco/trunk/doc/agent.html?referer=');">agent JaCoCo</a>. Pour cela, il faut récupérer le ZIP de JaCoCo <a href="http://www.eclemma.org/jacoco/" onclick="pageTracker._trackPageview('/outgoing/www.eclemma.org/jacoco/?referer=');">ici</a>, l&#8217;agent se trouvant alors dans <i>lib/jacocoagent.jar</i>.</li>
</ul>
<p>Maintenant que ceci est en place, nous allons devoir indiquer à Surefire d&#8217;utiliser un agent Java spécifique (l&#8217;agent JaCoCo).<br />
Etant donné que nous n&#8217;avons besoin de cet agent qu&#8217;au moment de l&#8217;exécution des tests d&#8217;intégration, nous le définirons que pour le profil <code>run-it</code>.<br />
Au sein du <code>pom.xml</code> parent, j&#8217;ai donc ajouté :</p>
<pre class="brush: xml;">
    &lt;profiles&gt;
        &lt;!-- Profile used to run Integration Tests. In such case, we add the Java agent for JaCoCo... --&gt;
        &lt;profile&gt;
            &lt;id&gt;run-it&lt;/id&gt;
            &lt;activation&gt;
                &lt;property&gt;
                    &lt;name&gt;runIT&lt;/name&gt;
                    &lt;value&gt;true&lt;/value&gt;
                &lt;/property&gt;
            &lt;/activation&gt;
            &lt;build&gt;
                &lt;plugins&gt;
                    &lt;plugin&gt;
                        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                        &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
                        &lt;configuration&gt;
                            &lt;argLine&gt;-javaagent:${jacoco.agent.path}=destfile=${jacoco.file.path}&lt;/argLine&gt;
                        &lt;/configuration&gt;
                    &lt;/plugin&gt;
                &lt;/plugins&gt;
            &lt;/build&gt;
        &lt;/profile&gt;
    &lt;/profiles&gt;
</pre>
<p>J&#8217;ai défini mon profil deux fois, dans le <code>pom.xml</code> parent et dans celui de <i>module-tests</i>. Nous aurions pu tout mettre dans le parent.</p>
<h2>Execution</h2>
<p>Nous allons avoir besoin d&#8217;exécuter maintenant deux commandes Maven :</p>
<ul>
<li>mvn clean install -DrunIT=true -Djacoco.agent.path=C:\dev\jacocoagent.jar -Djacoco.file.path=C:\dev\monprojet\jacoco.exec</li>
<li>mvn -Dsonar.jacoco.itReportPath=C:\dev\monprojet\jacoco.exec sonar:sonar</li>
</ul>
<p>La première ligne va activer le profil <i>run-it</i>, ce qui aura pour conséquence de lancer le tests d&#8217;intégration.<br />
On y définit les deux paramètres (<code>jacoco.agent.path</code> et <code>jacoco.file.path</code>) qui seront passés à Surefire pour définir un agent Java.</p>
<p>La seconde ligne va simplement exécuter l&#8217;analyse Sonar sur mon projet, mais en définissant le paramètre <code>sonar.jacoco.itReportPath</code> (généré lors de la première commande), cette analyse comprendra également la couverture des tests d&#8217;intégration.</p>
<p>Une fois les deux commandes exécutées, il suffit de se rendre sur son serveur Sonar pour apprécier cette nouvelle mesure de couverture de code !</p>
<p>Comme le montre <a href="http://www.sonarsource.org/measure-code-coverage-by-integration-tests-with-sonar/" onclick="pageTracker._trackPageview('/outgoing/www.sonarsource.org/measure-code-coverage-by-integration-tests-with-sonar/?referer=');">les captures d&#8217;écran sur le post du blog de Sonar à ce sujet</a>, il est possible, à l&#8217;instar de la couverture de code, de visualiser la couverture de code de tests d&#8217;intégration directement dans la fenêtre de visualisation du code source d&#8217;une classe.</p>
<p><img src="http://linsolas.free.fr/wordpress/wp-content/uploads/it-code-coverage.jpg"/></p>
<a href="javascript:toggleStartStop();PicLensLite.start({feedUrl:'http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/mrss.php?id=159'});">Start Slide Show with PicLens Lite <img src="http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/PicLensButton.png" alt="PicLens" width="16" height="12" border="0" align="top"></a>]]></content:encoded>
			<wfw:commentRss>http://linsolas.free.fr/wordpress/index.php/2011/07/calculer-sa-couverture-de-code-par-les-tests-dintegration/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to categorize JUnit tests with Maven</title>
		<link>http://linsolas.free.fr/wordpress/index.php/2011/02/howto-categorize-junit-tests-with-maven/</link>
		<comments>http://linsolas.free.fr/wordpress/index.php/2011/02/howto-categorize-junit-tests-with-maven/#comments</comments>
		<pubDate>Thu, 17 Feb 2011 12:24:35 +0000</pubDate>
		<dc:creator>Romain</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[tests]]></category>

		<guid isPermaLink="false">http://linsolas.free.fr/wordpress/?p=152</guid>
		<description><![CDATA[NB: This article is the english version of my previous article, written in french. For some reasons, I wanted to categorize my JUnit tests, in order to run only a subset of them. But this is not as simple as it seems&#8230; Context In one of my projects, I have many unit tests. It appears [...]]]></description>
			<content:encoded><![CDATA[<p><em>NB: This article is the english version of <a href="http://linsolas.free.fr/wordpress/index.php/2011/02/categoriser-ses-tests-junit-avec-maven/">my previous article</a>, written in french.</em></p>
<p>For some reasons, I wanted to categorize my JUnit tests, in order to run only a subset of them.<br />
But this is not as simple as it seems&#8230;</p>
<p><span id="more-152"></span></p>
<h2>Context</h2>
<p>In one of my projects, I have many unit tests. It appears that many of them are not <em>unit</em> at all.<br />
Some of them require a real Oracle connection, some others need to load a complex Spring context&#8230;</p>
<p>My goal is to split these tests into several categories.</p>
<p>To ease the explanations, I will only consider the two following categories: <code>@FastTest</code> and <code>@SlowTest</code>.</p>
<h2>Possible solutions</h2>
<p><a href="http://www.junit.org" onclick="pageTracker._trackPageview('/outgoing/www.junit.org?referer=');">JUnit</a> introduced recently, in version 4.8, the <code>@Category</code> annotation (see <a href="http://kentbeck.github.com/junit/doc/ReleaseNotes4.8.html" onclick="pageTracker._trackPageview('/outgoing/kentbeck.github.com/junit/doc/ReleaseNotes4.8.html?referer=');">the changelog</a> and also <a href="http://weblogs.java.net/blog/johnsmart/archive/2010/04/25/grouping-tests-using-junit-categories-0" onclick="pageTracker._trackPageview('/outgoing/weblogs.java.net/blog/johnsmart/archive/2010/04/25/grouping-tests-using-junit-categories-0?referer=');">an example here</a>).<br />
The principle is to annotate a class (or a method) with <code>@Category</code>, and then to define the category on which it belongs. For my needs, I could write:</p>
<pre class="brush: java;">
// Interfaces that define my test categories
public interface FastTest { }
public interface SlowTest { }

@Category(SlowTest.class)
public class ASlowTest {
    @Test
    public void foo() { ... }
}

@Category(FastTest.class)
public class ARealUnitTest {
    @Test
    public void foo() { ... }
}
</pre>
<p>This seems pretty good. But if we go into the details, in order to run all the tests that belong to a specific category, I have to write:</p>
<pre class="brush: java;">
@RunWith(Categories.class)
@IncludeCategory(FastTest.class)
@SuiteClasses( { ARealUnitTest.class, AnotherRealUnitTest.class })
public class FastTestsSuite { }
</pre>
<p>Here comes the problem: I have to create a <code>Suite</code> (using the annotation <code>@SuiteClasses</code>) to define the classes that should be executed.<br />
That means I have to maintain a list of all the tests for a given <code>Suite</code>. The omissions are therefore likely to be frequent&#8230;</p>
<h2>Not using JUnit Suite?</h2>
<p>How to solve this problem? Here are some ideas:</p>
<ul>
<li>Write the JUnit <code>Suite</code> manually as I just explained before, but I may forget to maintain them&#8230;</li>
<li>Let a Maven plugin creates the <code>Suite</code>. I wrote such a plugin some years ago, and I can reuse it now. However, I need to define when this plugin should be executed. Indeed, as the purpose of this plugin is to create or modify Java classes, I can&#8217;t run it automatically or anytime. Moreover, it is possible that some classes should not be included in these suites. So this solution will not be considered here.</li>
<li>Use specific patterns for the filenames of the test classes. For example, the fast tests will be named <code>**FastTest.java</code>, while the other ones will be named <code>**SlowTest.java</code>. Then, I will configure Maven, and some profiles, to use the correct pattern regarding which kind of tests category I want to run. I will not consider this solution neither, as this may also lead to errors.</li>
<li>Use <a href="http://testng.org" onclick="pageTracker._trackPageview('/outgoing/testng.org?referer=');">TestNG</a> instead of JUnit. TestNG is another test framework, which provides some advanced features. One of them is the definition of <code>groups</code> that would be perfect for our needs, especially since Surefire (the test plugin for Maven) <a href="http://maven.apache.org/plugins/maven-surefire-plugin/examples/testng.html" onclick="pageTracker._trackPageview('/outgoing/maven.apache.org/plugins/maven-surefire-plugin/examples/testng.html?referer=');">natively supports them</a>. This is maybe the best solution for our current concern, but I want to keep JUnit, so, again, I will ignore this idea.</li>
<li>Modify the Surefire plugin (or why not JUnit directly?) in order to manage the <code>@Category</code> without having to define a <code>Suite</code>. However, this is not a good idea to modify these libraries&#8230;</li>
</ul>
<p>So none of these ideas seems to be helpful&#8230;</p>
<h2>The last idea: Using JUnit Suite!</h2>
<p>The solution I will explain now is based on JUnit <code>Suite</code>. However, these suites will define <b>dynamically</b> the test classes that should be run.<br />
This <code>Suite</code> will look into the classpath for all the classes that are annotated with a particular annotation.</p>
<p>During <a href="http://stackoverflow.com/questions/2176570/how-to-run-all-tests-belonging-to-a-certain-category-in-junit-4" onclick="pageTracker._trackPageview('/outgoing/stackoverflow.com/questions/2176570/how-to-run-all-tests-belonging-to-a-certain-category-in-junit-4?referer=');">my searches</a>, I found a project called <a href="http://johanneslink.net/projects/cpsuite.jsp" onclick="pageTracker._trackPageview('/outgoing/johanneslink.net/projects/cpsuite.jsp?referer=');">classpathSuite</a>. One of the purpose of this project is to build a <code>Suite</code> by looking into the ClassPath for some specific classes. Exactly what I want to do!</p>
<p>Using this library, I write the following classes:</p>
<pre class="brush: java;">
@RunWith(Categories.class)
@Categories.IncludeCategory(FastTest.class)
@Suite.SuiteClasses( { AllTests.class })
public class FastTestsSuite {
}

@RunWith(ClasspathSuite.class)
public class AllTests {
}
</pre>
<p>and classpathSuite will find all the classes in the ClassPath that belong to the category <code>FastTest</code>.<br />
Nice! But this seems to work only when I run my tests in Eclipse, not in a Maven context <img src='http://linsolas.free.fr/wordpress/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />  <a href="http://stackoverflow.com/questions/4970196/running-all-tests-from-a-category-using-maven" onclick="pageTracker._trackPageview('/outgoing/stackoverflow.com/questions/4970196/running-all-tests-from-a-category-using-maven?referer=');">Or did I miss something?</a></p>
<p>So I have to re-implement this feature, but that will work with Maven!</p>
<h2>The solution</h2>
<p>First step: I create two simple annotations, <code>@FastTest</code> and <code>@SlowTest</code>.<br />
They will be used to annotate my JUnit test classes. Note that my solution will only allow you to categorize an entire class, not a method. These annotations will be a replacement for <code>@Category(FastTest.class)</code> and <code>@Category(SlowTest.class)</code>.</p>
<p>Now, I create a utility class that will look into the classpath and find the list of classes that are annotated with a specific annotation (<code>@FastTest</code> or <code>@SlowTest</code> in my case) and that belong to a given package (this condition is not technically mandatory, it is just to limit the searches).</p>
<p>On the Java point of view, I get:</p>
<pre class="brush: java;">
public final class ClasspathClassesFinder {

    /**
     * Get the list of classes of a given package name, and that are annotated by a given annotation.
     *
     * @param packageName The package name of the classes.
     * @param testAnnotation The annotation the class should be annotated with.
     * @return The List of classes that matches the requirements.
     */
    public static Class&lt;?&gt;[] getSuiteClasses(String packageName, Class&lt;? extends Annotation&gt; testAnnotation) {
        try {
            return getClasses(packageName, testAnnotation);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Get the list of classes of a given package name, and that are annotated by a given annotation.
     *
     * @param packageName The package name of the classes.
     * @param annotation The annotation the class should be annotated with.
     * @return The List of classes that matches the requirements.
     * @throws ClassNotFoundException If something goes wrong...
     * @throws IOException If something goes wrong...
     */
    private static Class&lt;?&gt;[] getClasses(String packageName, Class&lt;? extends Annotation&gt; annotation) throws ClassNotFoundException, IOException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        String path = packageName.replace('.', '/');
        // Get classpath
        Enumeration&lt;URL&gt; resources = classLoader.getResources(path);
        List&lt;File&gt; dirs = new ArrayList&lt;File&gt;();
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            dirs.add(new File(resource.getFile()));
        }
        // For each classpath, get the classes.
        ArrayList&lt;Class&lt;?&gt;&gt; classes = new ArrayList&lt;Class&lt;?&gt;&gt;();
        for (File directory : dirs) {
            classes.addAll(findClasses(directory, packageName, annotation));
        }
        return classes.toArray(new Class[classes.size()]);
    }

    /**
     * Find classes, in a given directory (recursively), for a given package name, that are annotated by a given annotation.
     *
     * @param directory The directory where to look for.
     * @param packageName The package name of the classes.
     * @param annotation The annotation the class should be annotated with.
     * @return The List of classes that matches the requirements.
     * @throws ClassNotFoundException If something goes wrong...
     */
    private static List&lt;Class&lt;?&gt;&gt; findClasses(File directory, String packageName, Class&lt;? extends Annotation&gt; annotation)
            throws ClassNotFoundException {
        List&lt;Class&lt;?&gt;&gt; classes = new ArrayList&lt;Class&lt;?&gt;&gt;();
        if (!directory.exists()) {
            return classes;
        }
        File[] files = directory.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                classes.addAll(findClasses(file, packageName + &quot;.&quot; + file.getName(), annotation));
            } else if (file.getName().endsWith(&quot;.class&quot;)) {
                // We remove the .class at the end of the filename to get the class name...
                Class&lt;?&gt; clazz = Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6));
                // Does the file is annotated with the given annotation?
                if (clazz.getAnnotation(annotation) != null) {
                    classes.add(clazz);
                }
            }
        }
        return classes;
    }
</pre>
<p>NB: I used the example given in <a href="http://snippets.dzone.com/posts/show/4831" onclick="pageTracker._trackPageview('/outgoing/snippets.dzone.com/posts/show/4831?referer=');">this post</a> to write this code.</p>
<p>Thus, the code <code>ClasspathClassesFinder.getSuiteClasses("my.company", FastTest.class)</code> will return an array of classes that belong to the package <code>my.company</code> and annotated with <code>@FastTest</code>.</p>
<p>The next step consists in building a <code>Suite</code> that will use my utility class to find all the fast tests:</p>
<pre class="brush: java;">
public class FastTestsSuite extends org.junit.runners.Suite {

    public FastTestsSuite(Class&lt;?&gt; clazz, RunnerBuilder builder) throws InitializationError {
        this(builder, clazz, ClasspathClassesFinder.getSuiteClasses(&quot;my.company&quot;, FastTest.class));
    }

    public FastTestsSuite(RunnerBuilder builder, Class&lt;?&gt; clazz, Class&lt;?&gt;[] suiteClasses) throws InitializationError {
        super(builder, clazz, suiteClasses);
    }

}
</pre>
<p>Last class to write: the entry point for the Maven Surefire plugin (this class will only run <code>@FastTest</code>, so I will have to write the same class for <code>@SlowTest</code>):</p>
<pre class="brush: java;">
@RunWith(FastTestsSuite.class)
public class RunAllFastTests {

}
</pre>
<p>Now, I just need to configure Maven in order to run &laquo;&nbsp;only&nbsp;&raquo; this test:</p>
<pre class="brush: xml;">
&lt;plugin&gt;
    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
    &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
    &lt;configuration&gt;
        &lt;!-- Run only tests annotated with @FastTest. --&gt;
        &lt;includes&gt;
            &lt;include&gt;**/RunAllFastTests.java&lt;/include&gt;
        &lt;/includes&gt;
        ...
    &lt;/configuration&gt;
&lt;/plugin&gt;
</pre>
<p>Please note that if you are working on a project with multi-modules (this is my case), you will have to define this <code>RunAllFastTests.java</code> in <em>each</em> module.</p>
<p>Regarding the slow tests, I just have to define a Maven profile that will launch the <code>RunAllSlowTests</code> class, which calls the Suite <code>SlowTestsSuite</code>. This Suite will use the utility class to find all classes annotated with <code>@SlowTest</code>. My continuous integration server <strike>Hudson</strike> Jenkins will activate this profile during the nightly-builds.</p>
<h2>Conclusion</h2>
<p>Finally, this solution is not really complex, and when the mechanism is developed, you just have to annotate your JUnit test class with the adequate annotation. This is simple.</p>
<p>However, I am quite disappointed that JUnit, a widely used test framework, does not provide such a mechanism natively. I hope that it will change in the near future&#8230;</p>
<p>Feel free to post your comments if you think that my solution is not the best one to solve this kind of problem.</p>
<h2>Sources</h2>
<p><a href="http://twitter.com/jpbriend" onclick="pageTracker._trackPageview('/outgoing/twitter.com/jpbriend?referer=');">Jean-Philippe Briend</a> suggested me on Twitter to provide the sources of the classes. Here they are:</p>
<p><a href="http://linsolas.free.fr/wordpress/wp-content/uploads/maven-junit-categories.zip"><img src="http://linsolas.free.fr/wordpress/wp-content/uploads/icon_zip.png"/>ZIP</a></p>
<p>This project requires Maven 2 or 3, Java 1.6 and JUnit 4.8.1.</p>
<p>In addition to all the classes required for the mechanism, this project contains three basic unit tests:</p>
<ul>
<li><code>OneFastTest</code>, annotated with <code>@FastTest</code> ;</li>
<li><code>OneSlowTest</code>, annotated with <code>@SlowTest</code> ;</li>
<li><code>TestWithoutAnnotation</code>, without any annotation. As this test should not be executed, it contains a method that will call the JUnit <code>fail()</code> method. Thus, if this class is executed, the test will fail.</li>
</ul>
<p>If you run the command <code>mvn clean install</code>, only the class annotated with <code>@FastTest</code> will be executed.<br />
If you run the command <code>mvn clean install -Djenkins=true</code> (or <code>-Pjenkins</code>), both annotated classes will be executed.</p>
<a href="javascript:toggleStartStop();PicLensLite.start({feedUrl:'http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/mrss.php?id=152'});">Start Slide Show with PicLens Lite <img src="http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/PicLensButton.png" alt="PicLens" width="16" height="12" border="0" align="top"></a>]]></content:encoded>
			<wfw:commentRss>http://linsolas.free.fr/wordpress/index.php/2011/02/howto-categorize-junit-tests-with-maven/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Catégoriser ses tests JUnit avec Maven</title>
		<link>http://linsolas.free.fr/wordpress/index.php/2011/02/categoriser-ses-tests-junit-avec-maven/</link>
		<comments>http://linsolas.free.fr/wordpress/index.php/2011/02/categoriser-ses-tests-junit-avec-maven/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 15:37:54 +0000</pubDate>
		<dc:creator>Romain</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[tests]]></category>

		<guid isPermaLink="false">http://linsolas.free.fr/wordpress/?p=139</guid>
		<description><![CDATA[J&#8217;ai eu envie de &#171;&#160;catégoriser&#160;&#187; mes tests JUnit, et de pouvoir ne lancer que certains d&#8217;entre eux via Maven. Ce qui semblait une tâche relativement simple s&#8217;est avérée être en réalité un chemin semé d&#8217;embuches&#8230; Voici mon carnet de voyage&#8230; Le contexte Dans l&#8217;un de mes projets, je dispose d&#8217;une grande quantité de tests unitaires. [...]]]></description>
			<content:encoded><![CDATA[<p>J&#8217;ai eu envie de &laquo;&nbsp;catégoriser&nbsp;&raquo; mes tests JUnit, et de pouvoir ne lancer que certains d&#8217;entre eux via Maven.<br />
Ce qui semblait une tâche relativement simple s&#8217;est avérée être en réalité un chemin semé d&#8217;embuches&#8230;</p>
<p>Voici mon carnet de voyage&#8230;</p>
<p><span id="more-139"></span></p>
<h2>Le contexte</h2>
<p>Dans l&#8217;un de mes projets, je dispose d&#8217;une grande quantité de tests <em>unitaires</em>.<br />
En réalité, parmi ceux-ci, beaucoup d&#8217;entre eux ne sont pas unitaires du tout. Ils nécessitent parfois un accès à la base Oracle, parfois un contexte Spring plutôt lourd à charger, etc. Bref, ce ne sont pas là de bons tests unitaires, lancés en isolation.</p>
<p>Le but est donc de pouvoir séparer les tests en diverses catégories.</p>
<p>Afin de simplifier les choses, je ne considèrerais que deux catégories ici : <code>@FastTest</code> et <code>@SlowTest</code>.</p>
<h2>Solutions envisagées</h2>
<p><a href="http://www.junit.org" onclick="pageTracker._trackPageview('/outgoing/www.junit.org?referer=');">JUnit</a> a introduit dans la version 4.8 les <code>@Category</code> (voir <a href="http://kentbeck.github.com/junit/doc/ReleaseNotes4.8.html" onclick="pageTracker._trackPageview('/outgoing/kentbeck.github.com/junit/doc/ReleaseNotes4.8.html?referer=');">le changelog</a> et <a href="http://weblogs.java.net/blog/johnsmart/archive/2010/04/25/grouping-tests-using-junit-categories-0" onclick="pageTracker._trackPageview('/outgoing/weblogs.java.net/blog/johnsmart/archive/2010/04/25/grouping-tests-using-junit-categories-0?referer=');">un exemple</a>).<br />
Le principe est d&#8217;annoter une classe (ou une méthode) avec <code>@Category</code>, et de définir à quelle catégorie ce(s) test(s) appartient(-nent). Pour notre besoin, nous pourrions donc écrire :</p>
<pre class="brush: java;">
// Interfaces pour catégoriser les tests...
public interface FastTest { }
public interface SlowTest { }

@Category(SlowTest.class)
public class ASlowTest {
    @Test
    public void foo() { ... }
}

@Category(FastTest.class)
public class ARealUnitTest {
    @Test
    public void foo() { ... }
}
</pre>
<p>Bref, ça s&#8217;annonce plutôt bien. Mais si l&#8217;on regarde dans le détail, pour pouvoir lancer tous les tests d&#8217;une catégorie spécifique, il faut faire :</p>
<pre class="brush: java;">
@RunWith(Categories.class)
@IncludeCategory(FastTest.class)
@SuiteClasses( { ARealUnitTest.class, AnotherRealUnitTest.class })
public class FastTestsSuite { }
</pre>
<p>Et c&#8217;est là notre souci : il faut créer une <code>Suite</code> (via l&#8217;annotation <code>@SuiteClasses</code>) afin de définir les classes devant être exécutées. Cela nous oblige donc à maintenir une liste exhaustive des tests à lancer pour une suite donnée. Les oublis risquent donc d’être fréquents&#8230;</p>
<h2>Se passer des Suite JUnit</h2>
<p>Comment pallier ce problème de <code>Suite</code> ? Rapidement, quelques idées me viennent :</p>
<ul>
<li>Ecrire des <code>Suite</code> manuellement comme on vient de le dire, mais avec le risque d&#8217;en oublier.</li>
<li>Ecrire des <code>Suite</code> via un plugin Maven. J&#8217;en avais écrit un dans ce but il y a environ 2 ans et je pourrais m&#8217;en resservir. Mais la question est de savoir à quel moment il doit être lancé. Etant donné que mon plugin écrit ou modifie des classes de tests, on ne peut pas l&#8217;exécuter automatiquement ni n&#8217;importe quand. De plus, il se peut que certaines classes ne doivent pas être ajoutées dans ces suites, donc on ne peut pas considérer cette solution comme viable.</li>
<li>Se baser sur des nommages spécifiques pour les classes de test. Par exemple tous les tests <em>vraiment</em> unitaires portent le nom de <code>***FastTest.java</code>, les autres étant nommés <code>***SlowTest.java</code>. Maven, et ses profiles, se chargeant ensuite de choisir quel pattern donné à Surefire. Bien qu’il s&#8217;agisse d&#8217;une idée intéressante, je ne suis que moyennement pour, car on risque d&#8217;avoir là aussi des oublis ou des erreurs.</li>
<li>Utiliser <a href="http://testng.org" onclick="pageTracker._trackPageview('/outgoing/testng.org?referer=');">TestNG</a>, un autre framework de tests, proposant plus de fonctionnalités que JUnit. En particulier, TestNG permet de créer des groupes sur les tests, ce qui correspond à nos <code>@Category</code> de JUnit, mais qui marchent mieux. Le plugin Maven de tests &#8211; Surefire &#8211; <a href="http://maven.apache.org/plugins/maven-surefire-plugin/examples/testng.html" onclick="pageTracker._trackPageview('/outgoing/maven.apache.org/plugins/maven-surefire-plugin/examples/testng.html?referer=');">gère nativement le support des groupes</a>. C&#8217;est très simple, il suffit de définir une propriété dans la configuration Maven du plugin Surefire ! Mais dans mon cas, je souhaite rester sur du JUnit, bien que cette solution soit sans doute la plus élégante&#8230;</li>
<li>Modifier le plugin surefire de Maven pour gérer les <code>@Category</code> de JUnit. Ne rigolez pas, j’ai essayé de le faire <img src='http://linsolas.free.fr/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Mais modifier un plugin du coeur de Maven n’est forcément pas une bonne idée !</li>
</ul>
<p>Sur ces cinq solutions, j&#8217;ai donc opté pour pour la sixième !</p>
<h2>La sixième solution : Ne pas se passer des Suite !</h2>
<p>L&#8217;idée consiste à utiliser des <code>Suite</code> de JUnit, mais que celles-ci soit générées dynamiquement.</p>
<p>Cette <code>Suite</code> va aller chercher dans le classpath les classes de tests annotées avec une annotation particulière.</p>
<p>Lors de mes <a href="http://stackoverflow.com/questions/2176570/how-to-run-all-tests-belonging-to-a-certain-category-in-junit-4" onclick="pageTracker._trackPageview('/outgoing/stackoverflow.com/questions/2176570/how-to-run-all-tests-belonging-to-a-certain-category-in-junit-4?referer=');">recherches</a>, je suis tombé sur le projet <a href="http://johanneslink.net/projects/cpsuite.jsp" onclick="pageTracker._trackPageview('/outgoing/johanneslink.net/projects/cpsuite.jsp?referer=');">classpathSuite</a>. L&#8217;un des intérêts de ce projet est de pouvoir construire une <code>Suite</code> en cherchant des classes présentes dans le ClassPath.</p>
<p>Ainsi il suffit d&#8217;écrire :</p>
<pre class="brush: java;">
@RunWith(Categories.class)
@Categories.IncludeCategory(FastTest.class)
@Suite.SuiteClasses( { AllTests.class })
public class FastTestsSuite {
}

@RunWith(ClasspathSuite.class)
public class AllTests {
}
</pre>
<p>pour que classpathSuite cherche toutes les classes présentes dans le ClassPath appartenant à la catégorie <code>FastTest</code>.<br />
Magique. Sauf que si ça marche très bien avec Eclipse, cela ne fonctionne pas lorsque les tests sont lancés par Maven.</p>
<p><a href="http://stackoverflow.com/questions/4970196/running-all-tests-from-a-category-using-maven" onclick="pageTracker._trackPageview('/outgoing/stackoverflow.com/questions/4970196/running-all-tests-from-a-category-using-maven?referer=');">Ou alors j&#8217;ai raté quelque chose !</a></p>
<p>Donc il faut refaire quelque chose de proche, mais qui marche avec Maven !</p>
<h2>La solution</h2>
<p>Première étape, je créé deux annotations simples : <code>@FastTest</code> et <code>@SlowTest</code>.<br />
Ces annotations vont être utilisées pour annoter des classes de tests unitaires (dans cette solution, nous n&#8217;annoterons que les classes, et pas les méthodes). Grosso-modo ça remplacera les annotations <code>@Category(FastTest.class)</code> et <code>@Category(SlowTest.class)</code>.</p>
<p>Ensuite, je crée une classe utilitaire qui va chercher dans tout le classpath les classes étant annotées par une annotation donnée (donc essentiellement <code>@FastTest</code> ou <code>@SlowTest</code>) et qui appartiennent à un package donné (ou un package fils).</p>
<p>Cela nous donne :</p>
<pre class="brush: java;">
public final class ClasspathClassesFinder {

    /**
     * Get the list of classes of a given package name, and that are annotated by a given annotation.
     *
     * @param packageName The package name of the classes.
     * @param testAnnotation The annotation the class should be annotated with.
     * @return The List of classes that matches the requirements.
     */
    public static Class&lt;?&gt;[] getSuiteClasses(String packageName, Class&lt;? extends Annotation&gt; testAnnotation) {
        try {
            return getClasses(packageName, testAnnotation);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Get the list of classes of a given package name, and that are annotated by a given annotation.
     *
     * @param packageName The package name of the classes.
     * @param annotation The annotation the class should be annotated with.
     * @return The List of classes that matches the requirements.
     * @throws ClassNotFoundException If something goes wrong...
     * @throws IOException If something goes wrong...
     */
    private static Class&lt;?&gt;[] getClasses(String packageName, Class&lt;? extends Annotation&gt; annotation) throws ClassNotFoundException, IOException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        String path = packageName.replace('.', '/');
        // Get classpath
        Enumeration&lt;URL&gt; resources = classLoader.getResources(path);
        List&lt;File&gt; dirs = new ArrayList&lt;File&gt;();
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            dirs.add(new File(resource.getFile()));
        }
        // For each classpath, get the classes.
        ArrayList&lt;Class&lt;?&gt;&gt; classes = new ArrayList&lt;Class&lt;?&gt;&gt;();
        for (File directory : dirs) {
            classes.addAll(findClasses(directory, packageName, annotation));
        }
        return classes.toArray(new Class[classes.size()]);
    }

    /**
     * Find classes, in a given directory (recurively), for a given package name, that are annotated by a given annotation.
     *
     * @param directory The directory where to look for.
     * @param packageName The package name of the classes.
     * @param annotation The annotation the class should be annotated with.
     * @return The List of classes that matches the requirements.
     * @throws ClassNotFoundException If something goes wrong...
     */
    private static List&lt;Class&lt;?&gt;&gt; findClasses(File directory, String packageName, Class&lt;? extends Annotation&gt; annotation)
            throws ClassNotFoundException {
        List&lt;Class&lt;?&gt;&gt; classes = new ArrayList&lt;Class&lt;?&gt;&gt;();
        if (!directory.exists()) {
            return classes;
        }
        File[] files = directory.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                classes.addAll(findClasses(file, packageName + &quot;.&quot; + file.getName(), annotation));
            } else if (file.getName().endsWith(&quot;.class&quot;)) {
                // We remove the .class at the end of the filename to get the class name...
                Class&lt;?&gt; clazz = Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6));
                // Does the file is annotated with the given annotation?
                if (clazz.getAnnotation(annotation) != null) {
                    classes.add(clazz);
                }
            }
        }
        return classes;
    }
</pre>
<p>NB: Je me suis inspiré de <a href="http://snippets.dzone.com/posts/show/4831" onclick="pageTracker._trackPageview('/outgoing/snippets.dzone.com/posts/show/4831?referer=');">ce post</a> pour ce code, mais adapté à mes besoins.<br />
Je n&#8217;ai pas regardé en détail, mais il est possible que <a href="http://code.google.com/p/reflections/" onclick="pageTracker._trackPageview('/outgoing/code.google.com/p/reflections/?referer=');">le projet Reflections</a> puisse faciliter l&#8217;écriture d&#8217;une telle classe, mais bon&#8230;</p>
<p>Ainsi, le code <code>ClasspathClassesFinder.getSuiteClasses("my.company", FastTest.class)</code> va me retourner un tableau de classes ayant comme package ancêtre <code>my.company</code> et annotées par <code>@FastTest</code>.</p>
<p>Je construit maintenant une <code>Suite</code> qui va utiliser cette précédente classe utilitaire pour me trouver les tests rapides :</p>
<pre class="brush: java;">
public class FastTestsSuite extends org.junit.runners.Suite {

    public FastTestsSuite(Class&lt;?&gt; clazz, RunnerBuilder builder) throws InitializationError {
        this(builder, clazz, ClasspathClassesFinder.getSuiteClasses(&quot;my.company&quot;, FastTest.class));
    }

    public FastTestsSuite(RunnerBuilder builder, Class&lt;?&gt; clazz, Class&lt;?&gt;[] suiteClasses) throws InitializationError {
        super(builder, clazz, suiteClasses);
    }

}
</pre>
<p>Dernier élément, le point d&#8217;entrée de mes tests pour le plugin Maven Surefire :</p>
<pre class="brush: java;">
@RunWith(FastTestsSuite.class)
public class RunAllFastTests {

}
</pre>
<p>Il ne me reste plus qu&#8217;à indiquer à Maven de ne prendre &laquo;&nbsp;que&nbsp;&raquo; ce test là :</p>
<pre class="brush: xml;">
&lt;plugin&gt;
    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
    &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
    &lt;configuration&gt;
        &lt;!-- Run only tests annotated with @FastTest. --&gt;
        &lt;includes&gt;
            &lt;include&gt;**/RunAllFastTests.java&lt;/include&gt;
        &lt;/includes&gt;
        ...
    &lt;/configuration&gt;
&lt;/plugin&gt;
</pre>
<p>Un petit bémol : si l&#8217;on travaille avec des projets multi-modules Maven (ce qui est mon cas), il faut que chaque module dispose de sa propre classe nommée <code>RunAllFastTests</code>.</p>
<p>Concernant les SlowTest, il me suffit de définir un profile Maven qui lancera la classe <code>RunAllSlowTests</code>, qui fera appel à la suite <code>SlowTestsSuite</code> qui appelle ma classe utilitaire pour trouver toutes les classes annotées par <code>@SlowTest</code>. Le serveur d&#8217;Intégration Continue <strike>Hudson</strike> Jenkins activant alors ce profile lors des nightly-builds.</p>
<h2>Conclusion</h2>
<p>Au final, il n&#8217;y a rien de bien méchant là-dedans, le principe une fois en place est simple (il suffit d&#8217;annoter la classe JUnit avec la bonne annotation). Mais je trouve cela regrettable que JUnit, pourtant très largement utilisé, soit aussi peu flexible pour un besoin somme toute très simple.</p>
<p>Donc si vous trouvez que j&#8217;ai sorti l&#8217;artillerie lourde pour rien, faites m&#8217;en part dans les commentaires, je suis curieux de voir comment vous vous y seriez pris !</p>
<h2>Bonus</h2>
<p>Suite à une suggestion de <a href="http://twitter.com/jpbriend" onclick="pageTracker._trackPageview('/outgoing/twitter.com/jpbriend?referer=');">Jean-Philippe Briend</a>, j&#8217;ai mis à disposition le code source d&#8217;un petit projet contenant toutes les classes évoquées ici.</p>
<p><a href="http://linsolas.free.fr/wordpress/wp-content/uploads/maven-junit-categories.zip"><img src="http://linsolas.free.fr/wordpress/wp-content/uploads/icon_zip.png"/> ZIP</a></p>
<p>Le projet se builde avec Maven 2 ou 3, Java 1.6 et JUnit 4.8.1.</p>
<p>En plus de toutes les classes nécessaires au bon fonctionnement du mécanisme, il contient trois classes de test unitaires, pour montrer le principe en action :</p>
<ul>
<li><code>OneFastTest</code>, annotée avec <code>@FastTest</code> ;</li>
<li><code>OneSlowTest</code>, annotée avec <code>@SlowTest</code> ;</li>
<li><code>TestWithoutAnnotation</code>, classe non annotée. Afin de montrer que ce test n&#8217;est pas exécuté, il contient une méthode qui appelle le <code>fail</code> de JUnit. Ainsi, si la classe est exécutée, le test échouera.</li>
</ul>
<p>En lançant la commande <code>mvn clean install</code>, seule la classe annotée avec <code>@FastTest</code> est exécutée.<br />
En lançant la commande <code>mvn clean install -Djenkins=true</code> (ou <code>-Pjenkins</code>), les deux classes annotées sont exécutées.</p>
<p>N&#8217;hésitez pas à me faire un retour sur ce projet si vous trouvez là aussi des énormités&#8230;</p>
<a href="javascript:toggleStartStop();PicLensLite.start({feedUrl:'http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/mrss.php?id=139'});">Start Slide Show with PicLens Lite <img src="http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/PicLensButton.png" alt="PicLens" width="16" height="12" border="0" align="top"></a>]]></content:encoded>
			<wfw:commentRss>http://linsolas.free.fr/wordpress/index.php/2011/02/categoriser-ses-tests-junit-avec-maven/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Tutoriel Play !</title>
		<link>http://linsolas.free.fr/wordpress/index.php/2010/02/tutoriel-play/</link>
		<comments>http://linsolas.free.fr/wordpress/index.php/2010/02/tutoriel-play/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 19:13:06 +0000</pubDate>
		<dc:creator>Romain</dc:creator>
				<category><![CDATA[article]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[play]]></category>

		<guid isPermaLink="false">http://linsolas.free.fr/wordpress/?p=111</guid>
		<description><![CDATA[Lors de mon précédent billet, j&#8217;avais évoqué le framework Play en montrant comment réaliser un simple Hello World. J&#8217;avais promis d&#8217;aller plus loin dans l&#8217;étude de ce framework, j&#8217;ai en fin de compte traduit l&#8217;intégralité du tutoriel présenté sur le site officiel. A travers ce tutoriel, vous pourrez découvrir plus de fonctionnalités de Play, d&#8217;apprendre [...]]]></description>
			<content:encoded><![CDATA[<p>Lors de mon <a href="http://linsolas.free.fr/wordpress/index.php/2010/01/jouons/">précédent billet</a>, j&#8217;avais évoqué le <a href="http://www.playframework.org" onclick="pageTracker._trackPageview('/outgoing/www.playframework.org?referer=');">framework Play</a> en montrant comment réaliser un simple Hello World.</p>
<p>J&#8217;avais promis d&#8217;aller plus loin dans l&#8217;étude de ce framework, j&#8217;ai en fin de compte traduit l&#8217;intégralité du tutoriel présenté sur le site officiel. A travers ce tutoriel, vous pourrez découvrir plus de fonctionnalités de Play, d&#8217;apprendre la façon dont il gère la persistence, comment créer des pages complexes, d&#8217;ajouter de l&#8217;authentification, etc.</p>
<p>Vous pouvez lire ma prose sur <a href="http://linsolas.developpez.com/articles/java/play/guide/" onclick="pageTracker._trackPageview('/outgoing/linsolas.developpez.com/articles/java/play/guide/?referer=');">mon site developpez.com</a> !</p>
]]></content:encoded>
			<wfw:commentRss>http://linsolas.free.fr/wordpress/index.php/2010/02/tutoriel-play/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Jouons !</title>
		<link>http://linsolas.free.fr/wordpress/index.php/2010/01/jouons/</link>
		<comments>http://linsolas.free.fr/wordpress/index.php/2010/01/jouons/#comments</comments>
		<pubDate>Tue, 05 Jan 2010 21:29:24 +0000</pubDate>
		<dc:creator>Romain</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[play]]></category>

		<guid isPermaLink="false">http://linsolas.free.fr/wordpress/?p=96</guid>
		<description><![CDATA[Non, rangez les Nintendo, je ne vais pas parler de jeu, mais de Play !. Play ! est donc un framework créé par Guillaume Bort qui s&#8217;apparente quelque peu à Grails, mais 100% orienté Java. Je laisse le touilleur donner quelques explications supplémentaires sur cet outil. Etape #1: Installons Play ! Pour installer Play!, rien [...]]]></description>
			<content:encoded><![CDATA[<p>Non, rangez les Nintendo, je ne vais pas parler de jeu, mais de <a href="http://www.playframework.org" onclick="pageTracker._trackPageview('/outgoing/www.playframework.org?referer=');">Play !</a>. <strong>Play !</strong> est donc un framework créé par <a href="http://guillaume.bort.fr/" onclick="pageTracker._trackPageview('/outgoing/guillaume.bort.fr/?referer=');">Guillaume Bort</a> qui s&#8217;apparente quelque peu à Grails, mais 100% orienté Java. Je <a href="http://www.touilleur-express.fr/2009/12/13/framework-play-a-decouvrir-le-jeudi-17-decembre/" onclick="pageTracker._trackPageview('/outgoing/www.touilleur-express.fr/2009/12/13/framework-play-a-decouvrir-le-jeudi-17-decembre/?referer=');">laisse le touilleur</a> donner quelques explications supplémentaires sur cet outil.</p>
<p><img class="aligncenter" title="Play !" src="http://www.playframework.org/images/play.png" alt="" width="177" height="64" /></p>
<h1>Etape #1: Installons Play !</h1>
<p>Pour installer <strong>Play!</strong>, rien de plus simple : il suffit de télécharger le ZIP (<a href="http://download.playframework.org/" onclick="pageTracker._trackPageview('/outgoing/download.playframework.org/?referer=');">ici</a>), puis de le décompresser sur son disque. C&#8217;est tout ! Pensons à ajouter le répertoire ainsi décompressé dans notre variable d&#8217;environnement Windows <em>PATH</em>, histoire de pouvoir taper la commande <strong>play</strong> en ligne de commande&#8230;</p>
<h1>Etape #2 : Démarrons !</h1>
<p>Allons à la racine de notre répertoire d&#8217;installation de <strong>Play!</strong>, et tapons la commande suivante :</p>
<pre class="brush: plain;">d:\developpement\play-1.0&gt; play new helloworld</pre>
<p>La commande nous demande alors quelle est le nom de notre nouvelle application :</p>
<pre class="brush: plain;">d:\developpement\play-1.0&gt;play new helloworld
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.0, http://www.playframework.org
~
~ The new application will be created in d:\developpement\play-1.0\helloworld
~ What is the application name? HelloWorld
~
~ OK, the application is created.
~ Start it with : play run heloworld
~ Have fun!
~</pre>
<p>Notre première application est prête ! Eh oui ! Voyons les choses plus en détails&#8230; Regardons le contenu du répertoire ainsi créé :</p>
<pre class="brush: plain;">app/
conf/
lib/
public/
test/</pre>
<p>Ces répertoires ont les rôles les suivants :</p>
<ul>
<li><em>app</em> : contient le code de l&#8217;application elle-même, à savoir les classes Java ainsi que les pages HTML.</li>
<li><em>conf</em> : les fichiers de configuration, en particulier <em>application.conf</em> qui contient les paramètres de notre application (par exemple le port du serveur, la configuration de la connection à la base de données, etc.), le fichier <em>routes</em>, qui définit les liens entre les URL et les pages web. Enfin, ce répertoire contient le fichier <em>messages</em> utilisé pour l&#8217;internationalisation du projet.</li>
<li><em>lib</em> : ce répertoire contient les librairies Java optionnelles.</li>
<li><em>public</em> : place contenant les ressources publiques, à savoir les images, les fichiers Javascript ou CSS.</li>
<li><em>test</em> : le répertoire permet de stocker les fichiers de tests, qu&#8217;il s&#8217;agisse de tests JUnit ou Selenium.</li>
</ul>
<p>Et  ça marche ? Voyons voir&#8230; Lançons la commande suivante :</p>
<pre class="brush: plain;">d:\developpement\play-1.0\helloworld&gt; play run</pre>
<pre class="brush: plain;">d:\developpement\play-1.0\helloworld&gt;play run
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.0, http://www.playframework.org
~
~ Ctrl+C to stop
~
Listening for transport dt_socket at address: 8000
20:15:17,611 INFO  ~ Starting d:\developpement\play-1.0\helloworld
20:15:20,579 WARN  ~ You're running Play! in DEV mode
20:15:22,111 INFO  ~ Listening for HTTP on port 9000 (Waiting a first request to start) ...</pre>
<p>Rendons-nous sur l&#8217;adresse <a href="http://localhost:9000" onclick="pageTracker._trackPageview('/outgoing/localhost_9000?referer=');">http://localhost:9000</a> (9000 étant le port par défaut du serveur <strong>Play !</strong>) pour visualiser la page par défaut :</p>
<p style="text-align: center;"><img class="aligncenter" title="Page par défaut de Play !" src="http://www.playframework.org/documentation/1.0/images/guide1-2" alt="" width="653" height="406" /></p>
<p>Mais quelle est la magie ? Le fichier <em>conf/routes</em> définit le routage des requêtes au sein de notre application. En particulier :</p>
<pre class="brush: plain;"># Home page
GET     /                                       Application.index</pre>
<p>Cette ligne indique que lorsqu&#8217;un utilisateur se connecte à la racine de notre application (ici http://localhost:9000/), sa requête sera prise en charge la <em>Application.index</em>. Ce contrôleur est visible dans <em>app/controlles/Application.java</em> :</p>
<pre class="brush: java;">package controllers;

import play.mvc.*;

public class Application extends Controller {

  public static void index() {
    render();
  }

}</pre>
<p>La première chose à constater ici c&#8217;est que notre contrôleur étend la classe <em>play.mvc.Controller</em>. Cette classe nous propose &#8211; entre autres &#8211; la méthode <em>render()</em> qui est ici utilisée dans l&#8217;action <em>index</em>. Cette action est par ailleurs définie comme une méthode publique et statique. C&#8217;est la façon de définir une action dans <strong>Play !</strong>. Dans cet exemple, cette dernière ne fait qu&#8217;afficher le contenu d&#8217;un template se trouvant dans <em>app/views/Application/index.html</em> (c&#8217;est le template utilisé par défaut, car nous n&#8217;en avons pas défini dans notre classe Java) :</p>
<pre class="brush: plain;">#{extends 'main.html' /}
#{set title:'Home' /}

#{welcome /}</pre>
<p>Ce template est divisé en trois parties. Tout d&#8217;abord, on y voit que notre template étend le <em>main.html</em> :</p>
<pre class="brush: xml;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;

&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;title&gt;#{get 'title' /}&lt;/title&gt;
    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;/&gt;
    &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;@{'/public/stylesheets/main.css'}&quot; /&gt;
    &lt;link rel=&quot;shortcut icon&quot; type=&quot;image/png&quot; href=&quot;@{'/public/images/favicon.png'}&quot; /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    #{doLayout /}
  &lt;/body&gt;
&lt;/html&gt;</pre>
<p>Dans ce fichier, on y voit le tag <em>#{doLayout /}</em> qui marque l&#8217;endroit où sera inseré le contenu du fichier <em>Application/index.html</em>.</p>
<p>Ensuite, on constate la façon dont un paramètre du template (le <em>title</em>) est passé à la page parente, via les <em>#{set &#8230;/}</em> et <em>#{get &#8230;/}</em>.</p>
<p>Enfin, la partie <em>#{welcome /}</em> génère le message d&#8217;accueil que nous avons pu voir précédemment.</p>
<h1>Etape #3 :Utilisons Eclipse</h1>
<p>Pour faciliter le développement de notre application, nous utilisons Eclipse. Pour ce faire, utilisons la commande suivante :</p>
<pre class="brush: plain;">d:\developpement\play-1.0&gt; play eclipsify helloworld</pre>
<p><strong>Play !</strong> se charge alors de créer les fichiers nécessaires à Eclipse :</p>
<pre class="brush: plain;">d:\developpement\play-1.0&gt;play eclipsify helloworld
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.0, http://www.playframework.org
~
~ OK, the application is ready for eclipse
~ Use File/Import/General/Existing project to import d:\developpement\play-1.0\helloworld into eclipse
~
~ Use eclipsify again when you want to update eclipse configuration files.
~ However, it's often better to delete and re-import the project into your workspace since eclipse keeps dirty caches...
~</pre>
<p>Les fichiers nécessaires à l&#8217;importation du projet dans Eclipse sont désormais créés. Il s&#8217;agit du <em>.project</em>, <em>.classpath</em> et <em>.settings/</em>.</p>
<p>Voilà, nous avons notre première petite application <strong>Play !</strong> qui tourne. On a vu deux ou trois concepts intéressants, mais il y a encore plein de jolies choses à découvrir sur ce framework (si vous avez suivi le lien du Touilleur que je vous ai donné en début de post, vous en avez déjà vu quelques unes) ! Nous les aborderons dans un prochain post, très bientôt !</p>
<h1>Bonus</h1>
<p>Voici la liste des options proposées par la commande <em>play</em> :</p>
<pre class="brush: plain;">C:\developpement\play-1.0\&gt;play help
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.0, http://www.playframework.org
~
~ For all commands, if the application is not specified, the current directory is used
~ Use 'play help cmd' to get more help on a specific command
~
~ Available commands are:
~ ~~~~~~~~~~~~~~~~~~~~~~~
~ auto-test      Automatically run all application tests
~ classpath      Display the computed classpath
~ clean          Delete temporary files (including the bytecode cache)
~ eclipsify      Create all eclipse configuration files
~ help           Display help on a specific command
~ id             Define the framework ID
~ modules        Display the computed modules list
~ netbeansify    Create all netbeans configuration files
~ new            Create a new application
~ out            Follow logs/system.out file
~ pid            Show the pid of a running application
~ precompile     Precompile all Java sources and templates to speed up application start
~ run            Run the application in the current shell
~ restart        Restart the running application
~ secret         Generate a new secret key
~ status         Display the status of the running application
~ start          Start the application in background
~ stop           Stop the running application
~ test           Run the application in test mode in the current shell
~ war            Export the application as a standalone WAR archive
~
~ Also refer to documentation at http://www.playframework.org/documentation
~</pre>
<a href="javascript:toggleStartStop();PicLensLite.start({feedUrl:'http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/mrss.php?id=96'});">Start Slide Show with PicLens Lite <img src="http://linsolas.free.fr/wordpress/wp-content/plugins/wp-piclens/PicLensButton.png" alt="PicLens" width="16" height="12" border="0" align="top"></a>]]></content:encoded>
			<wfw:commentRss>http://linsolas.free.fr/wordpress/index.php/2010/01/jouons/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
