<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="http://blog.philippebernard.fr/feed/rss2/xslt" ?><rss version="2.0"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <title>Test Logiciel et Assurance Qualité</title>
  <link>http://blog.philippebernard.fr/</link>
  <atom:link href="http://blog.philippebernard.fr/feed/rss2" rel="self" type="application/rss+xml"/>
  <description></description>
  <language>fr</language>
  <pubDate>Mon, 06 Sep 2010 19:11:37 +0200</pubDate>
  <copyright></copyright>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Dotclear</generator>
  
    
  <item>
    <title>5 trucs et astuces pour JUnit</title>
    <link>http://blog.philippebernard.fr/post/2010/05/23/5-trucs-et-astuces-pour-JUnit</link>
    <guid isPermaLink="false">urn:md5:0ca13940c9765b3910ea6749895a098c</guid>
    <pubDate>Sun, 23 May 2010 21:43:00 +0200</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
        <category>junit</category><category>outil</category><category>test</category>    
    <description>    &lt;p&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/icons/logo-junit-org.gif&quot; alt=&quot;JUnit&quot; style=&quot;float:left; margin: 0 1em 1em 0;&quot; title=&quot;JUnit, mai 2010&quot; /&gt; &lt;a href=&quot;http://www.junit.org/&quot;&gt;JUnit&lt;/a&gt; est &lt;em&gt;le&lt;/em&gt; framework de test unitaires
en Java. Il est désormais bien connu des développeurs Java et on le trouve
intégré à la majorité des IDE, Eclipse et NetBeans en tête.&lt;/p&gt;
&lt;p&gt;Se servir de JUnit est une chose. Ecrire des tests efficaces en est une
autre. Ce post n'a pas la prétention de livrer toutes les bonnes pratiques qui
entourent JUnit, mais donne quelques trucs qui peuvent servir à un moment ou à
un autre.&lt;/p&gt;
&lt;h2&gt;1- Définissez une classe de base pour vos tests&lt;/h2&gt;
&lt;p&gt;Un test JUnit doit hériter de &lt;code&gt;junit.framework.TestCase&lt;/code&gt;.
Cependant, pour un projet donné, on a souvent intérêt à créer une classe de
base pour tous les tests JUnit. Par exemple, pour le projet &amp;quot;Titato&amp;quot; :&lt;/p&gt;
&lt;pre&gt;
/**
 * All tests inherit this class.
 */
public abstract clas TitatoTestCase extends 
    junit.framework.TestCase {
}
&lt;/pre&gt;
&lt;p&gt;Puis chaque test du projet hérite de cette classe :&lt;/p&gt;
&lt;pre&gt;
/**
 * Test of ASpecificClass class.
 */
public class ASpecificClassTest extends TitatoTestCase {
  (...)
}
&lt;/pre&gt;
&lt;p&gt;L'intérêt ? Avoir un endroit où définir des méthodes utilitaires qui
pourront être utilisées par tous les tests du projet. Par exemple, JUnit ne
propose pas d'assertion pour comparer le contenu de tableaux de byte. Si on a
souvent besoin d'une telle assertion, &lt;code&gt;TitatoTestCase&lt;/code&gt; est l'endroit
approprié pour définir une telle méthode : elle sera accessible depuis
tous les tests.&lt;/p&gt;
&lt;h2&gt;2- Pour les larges comparaisons, préférez &lt;code&gt;assertEquals(String,
String)&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Toutes les assertions se valent... à priori. Pourtant, il y en a une
qu'Eclipse traite différemment : la comparaison de chaine. Si on compare
deux chaines différentes, Eclipse effectue un diff. Très pratique lorsque les
chaines sont longues.&lt;/p&gt;
&lt;p&gt;La comparaison :&lt;/p&gt;
&lt;pre&gt;
public void testStrings() {
  assertEquals(
    &amp;quot;This is a string\nAnd this is another one&amp;quot;,
    &amp;quot;This is a string\nAnd this is another ONE!&amp;quot;);
}
&lt;/pre&gt;
&lt;p&gt;produit :&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.philippebernard.fr/public/posts/5-trucs-et-astuces-pour-JUnit/assert_string.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/5-trucs-et-astuces-pour-JUnit/.assert_string_m.jpg&quot; alt=&quot;Comparaison de chaines&quot; title=&quot;Comparaison de chaines, mai 2010&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pour tirer parti de cette fonctionnalité, il suffit de rappeler
&lt;code&gt;assertEquals(String, String)&lt;/code&gt;, plutôt qu'une de ses variantes.
Prenons une comparaison de liste :&lt;/p&gt;
&lt;pre&gt;
public testGetPeopleList() {
  ArrayList&amp;lt;String&amp;gt; expected = new ArrayList&amp;lt;String&amp;gt;();
  expected.add(&amp;quot;John&amp;quot;);
  expected.add(&amp;quot;Bob&amp;quot;);
  expected.add(&amp;quot;Paul&amp;quot;);
  expected.add(&amp;quot;Michael&amp;quot;);

  assertEquals(expected, getPeopleList());
}
&lt;/pre&gt;
&lt;p&gt;En exécutant le test tel quel, Eclipse livre un message peu
lisible :&lt;/p&gt;
&lt;p&gt;junit.framework.AssertionFailedError: expected:&amp;lt;&lt;a href=&quot;http://blog.philippebernard.fr/post/2010/05/23/John,%20Bob,%20Paul,%20Michael&quot; title=&quot;John, Bob, Paul, Michael&quot;&gt;John, Bob,
Paul, Michael&lt;/a&gt;&amp;gt; but was:&amp;lt;&lt;a href=&quot;http://blog.philippebernard.fr/post/2010/05/23/John,%20Bob,%20Paul,%20Greg,%20Michael&quot; title=&quot;John, Bob, Paul, Greg, Michael&quot;&gt;John, Bob, Paul, Greg, Michael&lt;/a&gt;&amp;gt;&lt;/p&gt;
&lt;p&gt;Il y a une différence, mais quelle est-elle au juste ?&lt;/p&gt;
&lt;p&gt;En ramenant les listes à des chaines, on se simplifie la vie. Définissons
&lt;code&gt;assertEquals(ArrayList&amp;lt;String&amp;gt;, ArrayList&amp;lt;String&amp;gt;)&lt;/code&gt;,
probablement dans la classe mère des tests JUnit du projet, afin que celle-ci
soit utilisable partout :&lt;/p&gt;
&lt;pre&gt;
public void assertEquals(
    ArrayList&amp;lt;String&amp;gt; expected, 
    ArrayList&amp;lt;String&amp;gt; observed) {
  // Let's call assertEquals(String, String)
  assertEquals(toString(expected), toString(observed));
}

private String toString(ArrayList&amp;lt;String&amp;gt; list) {
  String result = &amp;quot;&amp;quot;;
  for (String s: list) {
    result += s + &amp;quot;\n&amp;quot;;
  }
  return result;
}
&lt;/pre&gt;
&lt;p&gt;Cette fois-ci, l'erreur est évidente :&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.philippebernard.fr/public/posts/5-trucs-et-astuces-pour-JUnit/assert_array_list.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/5-trucs-et-astuces-pour-JUnit/.assert_array_list_m.jpg&quot; alt=&quot;Assertion pour les ArrayList&quot; title=&quot;Assertion pour les ArrayList, mai 2010&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dans &lt;code&gt;toString(ArrayList&amp;lt;String&amp;gt; list)&lt;/code&gt;, il est important
de noter qu'on insère des sauts de ligne entre chaque item de la liste. C'est
important puisque cela va avoir un impact sur la présentation du diff. Sans
cela, Eclipse affiche un diff portant sur une unique ligne. Nettement moins
lisible.&lt;/p&gt;
&lt;h2&gt;3- Ne prenez pas de risque pour le test d'exception&lt;/h2&gt;
&lt;p&gt;Les tests négatifs nécessitent régulièrement de vérifier qu'on obtient une
exception en cas d'appel erroné :&lt;/p&gt;
&lt;pre&gt;
public void testTouchyMethod {
  try {
    // touchyMethod shall throw a SomeException
    touchyMethod();
    fail(&amp;quot;An exception was expected&amp;quot;);
  }
  catch(SomeException e) {
    // Correct case
  }
}
&lt;/pre&gt;
&lt;p&gt;Le point faible de ce type de construction vient de l'appel à la méthode
&lt;code&gt;fail&lt;/code&gt; de JUnit, invoquée si &lt;code&gt;touchyMethod&lt;/code&gt; retourne au
lieu de lancer une exception. Cet appel est vite oublié. Si tel est le cas, le
test ne sert à rien, tout en donnant l'impression inverse.&lt;/p&gt;
&lt;p&gt;Afin d'éviter ce risque, on peut implémenter un helper :&lt;/p&gt;
&lt;pre&gt;
public abstract class ExceptionTester extends TestCase {
  public abstract void runTestedAction() throws Throwable;

  public ExceptionTester(Class expectedClass) {
    try {
      runTestedAction();
    }
    catch (Throwable t) {
      assertEquals(expectedClass, t.getClass());
      return;
    }
    fail(&amp;quot;Expected &amp;quot; + expectedClass + &amp;quot; but got no error&amp;quot;);
  }
}
&lt;/pre&gt;
&lt;p&gt;Puis, lorsqu'on a besoin de vérifier un lancement d'exception :&lt;/p&gt;
&lt;pre&gt;
public void testFailingMethod() {
  new ExceptionTester(Exception.class) {
    @Override
    public void runTestedAction() throws Throwable {
      touchyMethod();
    }
  };
}
&lt;/pre&gt;
&lt;p&gt;Cette seconde version n'est guère plus compacte, mais là n'est pas
l'intérêt. Les avantages :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Par le jeu de la complétion des IDE modernes, elle est beaucoup plus rapide
à saisir. Notamment, Eclipse va déclarer &lt;code&gt;runTestedAction&lt;/code&gt; de
lui-même.&lt;/li&gt;
&lt;li&gt;Cette forme est plus sûre : pas d'appel à &lt;code&gt;fail&lt;/code&gt; à
oublier.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4- Utilisez des fichiers sans dépendre de leur chemin absolu&lt;/h2&gt;
&lt;p&gt;Un test doit pouvoir d'exécuter dans tout environnement. Lorsqu'on a besoin
d'utiliser un fichier à partir d'un test, il est tentant d'utiliser un chemin
absolu mais nous savons tous où cela mène...&lt;/p&gt;
&lt;p&gt;La &lt;a href=&quot;http://www.javaworld.com/jw-12-2000/jw-1221-junit.html?page=3&quot;&gt;solution
généralement recommandée&lt;/a&gt; est d'utiliser &lt;code&gt;getResource&lt;/code&gt; et
&lt;code&gt;getResourceAsStream&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;
InputStream is = this.getClass().getResourceAsStream(&amp;quot;data.txt&amp;quot;);
&lt;/pre&gt;
&lt;p&gt;C'est un début. Utiliser ces méthodes directement présente néanmoins une
difficulté. Comme elles prennent comme référence le répertoire de la classe, le
test JUnit dans notre cas, on doit souvent se fendre d'un conséquent
&lt;code&gt;&amp;quot;../../../..&amp;quot;&lt;/code&gt; avant d'atteindre le répertoire ciblé.&lt;/p&gt;
&lt;p&gt;Une bonne technique est de régler ces problème une fois pour toute, dans la
classe mère des tests JUnit du projet :&lt;/p&gt;
&lt;pre&gt;
public InputStream getResourceAsStream(String path) 
    throws IOException {
  // Get the path of the JUnit test base class
  URL url = SampleTestCase.class.getResource(
    &amp;quot;TitatoTestCase.class&amp;quot;);
  // Get the directory of the class
  // (ie. the TitatoTestCase.class file)
  // This method assume that TitatoTestCase is not located 
  // in a JAR file
  File file = new File(url.getPath());
  // Here, the &amp;quot;/../&amp;quot; depends on the project layout
  return new FileInputStream(file.getParent() + &amp;quot;/../&amp;quot; + path);
}
&lt;/pre&gt;
&lt;p&gt;Cette méthode doit être adaptée pour chaque projet :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;TitatoTestCase.class&amp;quot;&lt;/code&gt; dépend du nom de la classe de base des
tests JUnit.&lt;/li&gt;
&lt;li&gt;Dans la dernière ligne, &lt;code&gt;&amp;quot;/../&amp;quot;&lt;/code&gt; est destiné à se placer au
niveau du projet. Ce composant dépend de l'endroit où est compilée la classe
ainsi que son package.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Enfin, chaque test peut ouvrir un fichier :&lt;/p&gt;
&lt;pre&gt;
getResourceAsStream(&amp;quot;test/test_data/data.txt&amp;quot;);
&lt;/pre&gt;
&lt;h2&gt;5- Test de séquences complexes : utilisez des traces sous la forme de
String&lt;/h2&gt;
&lt;p&gt;Certain tests consistent à vérifier que telle ou telle méthode a bien été
appelée. C'est régulièrement le cas lorsqu'on implémente le design pattern
&lt;a href=&quot;http://en.wikipedia.org/wiki/Template_method_pattern&quot;&gt;Template
method&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Prenons l'exemple d'une classe &lt;code&gt;FileHelper&lt;/code&gt;. Cette classe possède
une méthode &lt;code&gt;process&lt;/code&gt; qui prend en paramètre un nom de fichier ainsi
qu'un &lt;code&gt;FileProcessor&lt;/code&gt;. &lt;code&gt;FileProcessor&lt;/code&gt; est une interface
dotée de 3 méthodes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fileOpened(String fileName)&lt;/code&gt; : appelée lorsque le fichier
à traiter est ouvert ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lineRead(String line)&lt;/code&gt; : appelée pour chaque ligne du
fichier traité ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fileClosed()&lt;/code&gt; : appelé lorsque le fichier traité est
fermé.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lorsqu'on appelle &lt;code&gt;FileHelper.process(&amp;quot;myFile.txt&amp;quot;, aProcessor)&lt;/code&gt;,
on s'attend à la équence suivante :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aProcessor.fileOpened&lt;/code&gt; est appelé avec
&lt;code&gt;&amp;quot;myFile.txt&amp;quot;&lt;/code&gt; ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aProcessor.lineRead&lt;/code&gt; est appelé pour chaque ligne du
fichier ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aProcessor.fileClosed&lt;/code&gt; est appelé.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Comment tester &lt;code&gt;FileHelper.process&lt;/code&gt; ? Une solution pratique
est de tracer l'exécution au sein d'une instance de &lt;code&gt;FileProcessor&lt;/code&gt;
et de comparer cette trace avec le résultat attendu.&lt;/p&gt;
&lt;p&gt;On commence par créer un fichier d'exemple, nommé
&lt;code&gt;data_for_filehelper_process.txt&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;
This is a sample file
to test FileHelper.process
Bye!
&lt;/pre&gt;
&lt;p&gt;On implémente &lt;code&gt;FileProcessor&lt;/code&gt;. Cette implémentation ne fait rien
d'autre que sauver la trace des méthodes qui sont appelées :&lt;/p&gt;
&lt;pre&gt;
public class TestProcessor implements FileProcessor {
  String trace = &amp;quot;&amp;quot;;
  public void fileOpened(String fileName) {
    trace += &amp;quot;fileOpened(&amp;quot; + fileName + &amp;quot;)\n&amp;quot;;
  }
  public void lineRead(String line) {
    trace += &amp;quot;lineRead(&amp;quot; + line + &amp;quot;)\n&amp;quot;;
  }
  public void fileClosed() {
    trace += &amp;quot;fileClosed()\n&amp;quot;;
  }
  public String getTrace() {
    return trace;
  }
}
&lt;/pre&gt;
&lt;p&gt;Il ne reste plus qu'à implémenter le test :&lt;/p&gt;
&lt;pre&gt;
public void testProcess() {
  TestProcessor processor = new TestProcessor();
  // For an idea of how getResourcePath should work, 
  // see previous section above
  FileHelper.process(getResourcePath(
    &amp;quot;test/test_data/data_for_filehelper_process.txt&amp;quot;), 
    processor);
  // Check the trace
  assertEquals(
    &amp;quot;fileOpened(data_for_filehelper_process.txt)\n&amp;quot; +
    &amp;quot;lineRead(This is a sample file)\n&amp;quot; +
    &amp;quot;lineRead(to test FileHelper.process)\n&amp;quot; +
    &amp;quot;lineRead(Bye!)\n&amp;quot; +
    &amp;quot;fileClosed()\n&amp;quot;, 
    processor.getTrace());
}
&lt;/pre&gt;
&lt;p&gt;Si &lt;code&gt;FileHelper.process&lt;/code&gt; est buggué et omet de lire la dernière
ligne du fichier, on obtiendra sous Eclipse :&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.philippebernard.fr/public/posts/5-trucs-et-astuces-pour-JUnit/trace_testing.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/5-trucs-et-astuces-pour-JUnit/.trace_testing_m.jpg&quot; alt=&quot;Trace testing&quot; title=&quot;Trace testing, mai 2010&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Bon test avec JUnit !&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2010/05/23/5-trucs-et-astuces-pour-JUnit#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2010/05/23/5-trucs-et-astuces-pour-JUnit#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/501057</wfw:commentRss>
      </item>
    
  <item>
    <title>La Journée Française des Tests Logiciels du 30 mars 2010</title>
    <link>http://blog.philippebernard.fr/post/2010/04/25/La-Journ%C3%A9e-Fran%C3%A7aise-des-Tests-Logiciels-du-30-mars-2010</link>
    <guid isPermaLink="false">urn:md5:b91e949eb5e11a78dd8e2c65cb362d84</guid>
    <pubDate>Sun, 25 Apr 2010 19:20:00 +0200</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
        <category>cftl</category><category>test</category>    
    <description>    &lt;p&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/La-Journee-Francaise-des-Tests-Logiciels-du-30-mars-2010/.JFTL10_CFTL_t.jpg&quot; alt=&quot;Journée Française des Tests Logiciels&quot; style=&quot;float:left; margin: 0 1em 1em 0;&quot; title=&quot;Journée Française des Tests Logiciels, avr. 2010&quot; /&gt; J'ai participé il y a
quelques jours à la seconde Journée Français des Tests Logiciels, à deux pas de
la Tours Eiffel. Présentations, exposants et petits fours... Bref, une
conférence dédiée, fait rare, au test logiciel. Le tout organisé par le CFTL et
animé par Bernard Homès, son président.&lt;/p&gt;
&lt;p&gt;Les présentations ont été à la hauteur de mes espérances. De bonne qualité
et informatives. J'ai hélas raté &amp;quot;Mais qu’est ce qui cloche avec mes métriques
?&amp;quot;, proposée par &lt;a href=&quot;http://www.pstestware.fr/&quot;&gt;ps_testware&lt;/a&gt; et qui a
reçu le prix de la meilleure présentation de la journée. Mais les sessions sur
les examens du CFTL ou l'intérêt économique du test étaient également très
intéressantes. Les participants ont aussi pu discuter avec une quinzaine
d'exposants : SSII, spécialistes du test, formateurs... Cela nous a donné
l'occasion de partager expériences, points de vue et cartes de visite. J'ai si
peu l'occasion de discuter avec des testeurs d'autres sociétés, voilà qui fait
plaisir !&lt;/p&gt;
&lt;p&gt;Petite déception toutefois : pas de spécialistes de l'embarqué parmi
les exposants. &lt;a href=&quot;http://www.kereval.com/&quot;&gt;Kereval&lt;/a&gt; a bien fait une
présentation, à laquelle je n'ai pas assisté. Dommage, la lecture des slides à
postériori m'a bien plu, peut-être aurais-je du changer mon choix. &lt;a href=&quot;http://www.smartesting.com/&quot;&gt;Smartesting&lt;/a&gt; a également des projets dans le
domaines de la carte, mais c'est de SAP dont il était question lors de leur
présentation. L'embarqué et son représentant le plus populaire, le smartphone,
prennent de plus en plus d'importance. Cette relative absence sera j'en suis
sûr corrigée lors de la prochaine édition !&lt;/p&gt;
&lt;p&gt;Cette journée a été un succès : plus de 300 participants, contre 250
prévus initialement. Pas mal le test ! Au delà de ce signe positif, on a
pu sentir une montée de la discipline. Bernard Homès citait un fait
intéressant : l'année passée, les embauches de développeurs ont diminué,
crise oblige, tandis que celles des testeurs ont un peu augmenté. Simple
hasard ? Je ne crois pas. Le test reste trop peu professionnalisé, comme
je le regrettais dans un &lt;a href=&quot;http://blog.philippebernard.fr/post/2009/12/05/Qu-ai-je-appris-sur-le-Test-Logiciel-en-tant-qu-%C3%A9tudiant&quot;&gt;
précédent billet&lt;/a&gt;. Or les attentes vis à vis des logiciels sont de plus en
plus fortes. Plus un poste ou un foyer sans PC. Impossible de ne pas être
connecté. Inacceptable de perdre ses données. L'exigence de qualité est la
contrepartie du succès du logiciel. Cet aspect est encore en retrait. A nous,
testeurs, de relever le défi !&lt;/p&gt;
&lt;p&gt;Au vote informel qui s'est tenu en fin de journée pour savoir s'il fallait
renouveler la JFTL dès l'année prochaine, c'est une large majorité de &amp;quot;oui&amp;quot; qui
l'a emporté. Merci aux organisateurs, et à l'année prochaine !&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2010/04/25/La-Journ%C3%A9e-Fran%C3%A7aise-des-Tests-Logiciels-du-30-mars-2010#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2010/04/25/La-Journ%C3%A9e-Fran%C3%A7aise-des-Tests-Logiciels-du-30-mars-2010#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/484000</wfw:commentRss>
      </item>
    
  <item>
    <title>Tutoriel : Tester une application Android avec Monkey</title>
    <link>http://blog.philippebernard.fr/post/2010/03/13/Tutoriel-%3A-Tester-une-application-Android-avec-Monkey</link>
    <guid isPermaLink="false">urn:md5:dbeea5ebeb2ed41a9781ccaf37300226</guid>
    <pubDate>Sat, 13 Mar 2010 20:01:00 +0100</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
        <category>Tutoriels</category>
        <category>android</category><category>outil</category><category>test</category><category>tutoriel</category>    
    <description>    &lt;p&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/icons/android-logo.jpg&quot; alt=&quot;Android Logo&quot; style=&quot;float:left; margin: 0 1em 1em 0;&quot; title=&quot;Android Logo, mar. 2010&quot; /&gt; &lt;a href=&quot;http://developer.android.com/guide/developing/tools/monkey.html&quot;&gt;Monkey&lt;/a&gt;
est un outil qui permet de tester une application Android. Plus précisément, il
simule des interactions &amp;quot;aveugles&amp;quot; avec l'application à vérifier. Contrairement
à la grande majorité des environnements de tests, Monkey n'a pas besoin d'être
piloté, ou alors très sommairement : on ne lui indique pas où cliquer, le
résultat attendu, etc. Il génère des interactions quelconques sans ce soucier
de la logique applicative et signale les erreurs évidentes, comme les
exceptions non traitées.&lt;/p&gt;
&lt;p&gt;Ce billet explique comment lancer Monkey et exploiter ses résultats. Il fait
référence à une application d'exemple fournie avec le SDK Android.&lt;/p&gt;
&lt;h2&gt;Préparation de l'environnement&lt;/h2&gt;
&lt;p&gt;Avant de lancer Monkey, nous avons besoin du SDK Android. Suivez les étapes
1 à 3 d'&lt;a href=&quot;http://developer.android.com/sdk/installing.html&quot;&gt;Installing
the SDK&lt;/a&gt;. Si vous développez sur Android ou si plus simplement vous avez
essayé le &lt;a href=&quot;http://developer.android.com/resources/tutorials/hello-world.html&quot;&gt;Hello
World&lt;/a&gt;, alors vous avez déjà tout ce qu'il faut.&lt;/p&gt;
&lt;p&gt;Nous avons également besoin d'une application à tester. Plutôt que d'en
écrire une pour l'occasion, nous allons partir de &lt;a href=&quot;http://developer.android.com/resources/tutorials/notepad/index.html&quot;&gt;NotePad&lt;/a&gt;,
une application d'exemple fournie avec le SDK.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Lancez Eclipse.&lt;/li&gt;
&lt;li&gt;Faites &lt;em&gt;File &amp;gt; New &amp;gt; Android Project&lt;/em&gt;. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/create_android_project.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.create_android_project_m.jpg&quot; alt=&quot;Création d'un projet&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Création d'un projet, mar. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dans le wizard, au lieu de créer une nouvelle application, on importe une
application d'exemple. Sélectionnez &lt;em&gt;Create project from existing
sample&lt;/em&gt;, dans le volet &lt;em&gt;Build Target&lt;/em&gt; sélectionnez &lt;em&gt;Android
1.6&lt;/em&gt; puis dans la liste &lt;em&gt;Samples&lt;/em&gt; choisissez &lt;em&gt;NotePad&lt;/em&gt;.
Cliquez sur &lt;em&gt;Finish&lt;/em&gt;. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/new_project_wizard.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.new_project_wizard_m.jpg&quot; alt=&quot;Wizard&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Wizard, mar. 2010&quot; /&gt;&lt;/a&gt; Le
projet est créé, il apparait dans le &lt;em&gt;Package Explorer&lt;/em&gt;, par défaut dans
la partie gauche d'Eclipse. Nous allons lancer NotePad, mais pour cela nous
avons besoin d'une instance Android virtuelle.&lt;/li&gt;
&lt;li&gt;Faites &lt;em&gt;Window &amp;gt; Android SDK and AVD Manager&lt;/em&gt;. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/android_manager.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.android_manager_s.jpg&quot; alt=&quot;Android SDK and AVD Manager&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Android SDK and AVD Manager, mar. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dans la fenêtre &lt;em&gt;Android SDK and AVD Manager&lt;/em&gt;, cliquez sur
&lt;em&gt;New...&lt;/em&gt; &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/android_manager_new.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.android_manager_new_m.jpg&quot; alt=&quot;Android SDK and AVD Manager - New&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Android SDK and AVD Manager - New, mar. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dans la fenêtre &lt;em&gt;Create New AVD&lt;/em&gt;, inscrivez Default_AVD en tant que
nom, choisissez &lt;em&gt;Android 1.6 - API Level 4&lt;/em&gt; dans la liste
&lt;em&gt;Target&lt;/em&gt; et entrez une taille de 1024 Mo pour la carte SD. Cliquez sur
&lt;em&gt;Create AVD&lt;/em&gt;. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/new_avd.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.new_avd_m.jpg&quot; alt=&quot;AVD Creation&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;AVD Creation, mar. 2010&quot; /&gt;&lt;/a&gt;
L'instance virtuelle est maintenant disponible. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/avd_created.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.avd_created_m.jpg&quot; alt=&quot;AVD created&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;AVD created, mar. 2010&quot; /&gt;&lt;/a&gt; Il
est tant de lancer Notepad.&lt;/li&gt;
&lt;li&gt;Cliquez-droit sur le projet NotesList et sélectionnez &lt;em&gt;Run As &amp;gt;
Android Application&lt;/em&gt;. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/run_as.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.run_as_m.jpg&quot; alt=&quot;Run NotePad&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Run NotePad, mar. 2010&quot; /&gt;&lt;/a&gt;
L'instance virtuelle se lance et après quelques dizaines de secondes, NotePad
est disponible. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/notepad.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.notepad_m.jpg&quot; alt=&quot;NotePad&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;NotePad, mar. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cliquez sur &lt;em&gt;Menu&lt;/em&gt; puis créez une note. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/notepad_add_note.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.notepad_add_note_m.jpg&quot; alt=&quot;NotePad - Add Note&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;NotePad - Add Note, mar. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Saisissez du texte et validez. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/notepad_create_note.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.notepad_create_note_m.jpg&quot; alt=&quot;NotePad - Edit Note&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;NotePad - Edit Note, mar. 2010&quot; /&gt;&lt;/a&gt; La note est créée. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/notepad_note_created.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.notepad_note_created_m.jpg&quot; alt=&quot;NotePad - Note Created&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;NotePad - Note Created, mar. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Lancer Monkey&lt;/h2&gt;
&lt;p&gt;NotePad fonctionne et nous pouvons à présent lancer Monkey.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Assurez-vous que l'émulateur est lancé. Si ce n'est pas le cas, suivez les
instructions ci-dessus de nouveau pour relancer NotePad.&lt;/li&gt;
&lt;li&gt;Ouvrez une console et rendez-vous dans le sous-répertoire
&lt;code&gt;tools&lt;/code&gt; du SDK Android. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/new_console.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.new_console_m.jpg&quot; alt=&quot;New console&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;New console, mar. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lancez Monkey avec la commande &lt;code&gt;adb shell monkey -p
com.example.android.notepad -v 500&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Monkey se connecte à l'instance virtuelle et effectue diverses actions,
comme le ferait un utilisateur... un utilisateur qui ne sait pas vraiment ce
qu'il veut car ses manipulations n'ont aucun but précis : modification
hasardeuse de la note existante mais sans sauver, modification du volume,
rotation de l'écran... Dans la console, on voit les différentes actions qui
sont déclenchées par Monkey tandis que la fenêtre de l'émulateur s'anime au fur
et à mesure.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/monkey_finished.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.monkey_finished_m.jpg&quot; alt=&quot;Monkey has finished&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Monkey has finished, mar. 2010&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Et en cas de bug ?&lt;/h2&gt;
&lt;p&gt;Monkey vient de jouer avec NotePad sans signaler quoi que ce soit d'anormal.
Que se passe-t-il lorsqu'une erreur se produit ? Voyons-voir ça.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Editez &lt;code&gt;NoteEditor.java&lt;/code&gt;. Après la ligne 175, insérez
&lt;code&gt;throw new RuntimeException(&amp;quot;Oh! Un bug!&amp;quot;);&lt;/code&gt; afin qu'une exception
soit déclenchée lors d'une édition. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/insert_bug.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.insert_bug_m.jpg&quot; alt=&quot;Insert a bug&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Insert a bug, mar. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sauvez.&lt;/li&gt;
&lt;li&gt;Relancez NotePad. Dans la barre d'outils cliquez sur &lt;em&gt;Run As...&lt;/em&gt;,
sélectionnez &lt;em&gt;Android Application&lt;/em&gt; et faites &lt;em&gt;Ok&lt;/em&gt;. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/rerun_notepad.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.rerun_notepad_m.jpg&quot; alt=&quot;Rerun NotePad&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Rerun NotePad, mar. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A partir de la console, relancez Monkey.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Cette fois-ci, les tentatives de Monkey ne devraient pas se faire sans
encombre. Après plus ou moins d'actions, Monkey tombe sur le bug et échoue. Il
affiche la stack trace qui permet de retrouver l'origine de l'erreur.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/monkey_fails.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_android_monkey/.monkey_fails_m.jpg&quot; alt=&quot;Monkey fails&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Monkey fails, mar. 2010&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Le mot de la fin&lt;/h2&gt;
&lt;p&gt;Monkey a le grand avantage de fonctionner immédiatement, sans nécessiter
l'écriture de tests. Naturellement, la contrepartie est cinglante : sans
aucune connaissance du fonctionnement attendu de l'application, Monkey ne sait
détecter que les erreurs plus bas niveau, celles qui provoquent une
récupération par le système. Attention donc à ne pas tomber dans le piège qui
consiste à se reposer entièrement sur Monkey, au détriment de véritables
tests.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2010/03/13/Tutoriel-%3A-Tester-une-application-Android-avec-Monkey#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2010/03/13/Tutoriel-%3A-Tester-une-application-Android-avec-Monkey#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/498691</wfw:commentRss>
      </item>
    
  <item>
    <title>Le test en Ruby on Rails : forfait, hors forfait</title>
    <link>http://blog.philippebernard.fr/post/2010/02/28/Le-test-en-Ruby-on-Rails-%3A-forfait%2C-hors-forfait</link>
    <guid isPermaLink="false">urn:md5:a800b34b6b65d9a10c4b07987c4dee3f</guid>
    <pubDate>Sun, 28 Feb 2010 14:32:00 +0100</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
        <category>ror</category><category>test</category>    
    <description>    &lt;p&gt;&lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Ruby on Rails&lt;/a&gt; est un framework web
fantastique. Il est &lt;a href=&quot;http://media.rubyonrails.org/video/rails_blog_2.mov&quot;&gt;puissant&lt;/a&gt;, on peut
faire de l'Ajax très facilement... Et il a une qualité qu'un compulsif du
&lt;a href=&quot;http://fr.wikipedia.org/wiki/Test_Driven_Development&quot;&gt;développement
piloté par les tests&lt;/a&gt; tel que moi ne peut qu'apprécier : le test fait
partie intégrante du framework.&lt;/p&gt;
&lt;h2&gt;Forfait&lt;/h2&gt;
&lt;p&gt;Fort heureusement, RoR inclut l'essentiel :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tests des modèles&lt;/li&gt;
&lt;li&gt;Tests des contrôleurs et des vues&lt;/li&gt;
&lt;li&gt;Test d'intégration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mieux : en RoR, les tests sont aussi naturels que le code lui-même.
Lorsqu'on crée un modèle ou un contrôleur, RoR crée non seulement ledit
contrôleur, mais aussi le test qui va avec.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.philippebernard.fr/public/posts/Le-test-en-Ruby-on-Rails-_-forfait-hors-forfait/controller.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/Le-test-en-Ruby-on-Rails-_-forfait-hors-forfait/.controller_m.jpg&quot; alt=&quot;Controller&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Controller, fév. 2010&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;RoR inclut également un environnement de test, c'est à dire une
configuration et une base de données dédiées au test. Cet environnement est
distinct de celui dont on se sert pour faire des essais à la main, de sorte que
les tests s'exécutent vraiment &amp;quot;dans leur coin&amp;quot; et sans interférence. La
bascule d'un environnement se fait très simplement (pour ne pas dire
automatiquement lorsqu'on lance les tests) et sans bidouillage : on ne
passe pas son temps à trafiquer un obscur fichier de configuration pour pointer
sur une base ou l'autre, ou toute autre manipulation douteuse de ce genre. RoR
fait tout cela proprement.&lt;/p&gt;
&lt;p&gt;L'environnement de test s'accompagne de fixtures, données qui servent à
initialiser la base de test. Des utilisateurs, des commandes, des produits...
tout ce qu'il faut pour que les tests puissent démarrer en ayant des données
sous la main.&lt;/p&gt;
&lt;h2&gt;Hors forfait&lt;/h2&gt;
&lt;p&gt;RoR n'est pas parfait, il manque quelques éléments et certains domaines
pourraient être complétés.&lt;/p&gt;
&lt;h3&gt;Tests des helpers&lt;/h3&gt;
&lt;p&gt;Les helpers hébergent le code spécifique aux vues qu'on pourrait être tenté
d'insérer directement dans les template ERB. Bon choix de design, les helpers
permettent de garder les vues aussi légères que possible.&lt;/p&gt;
&lt;p&gt;Malheureusement, point de test de helper. Pourtant la génération du
contrôleur serait le moment idéal pour créer le test du helper mais non, rien
de tel.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.philippebernard.fr/public/posts/Le-test-en-Ruby-on-Rails-_-forfait-hors-forfait/helper.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/Le-test-en-Ruby-on-Rails-_-forfait-hors-forfait/.helper_m.jpg&quot; alt=&quot;Helper&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Helper, fév. 2010&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;C'est dommage, puisque cela oblige à vérifier le résultat des helpers
directement dans les vues, dont le test est plus complexe et fragile. Rien
d'insurmontable toutefois, il existe un &lt;a href=&quot;http://nubyonrails.com/articles/test-your-helpers&quot;&gt;plugin pour tester les
helpers&lt;/a&gt;. Et RoR est pardonné pour cet écart.&lt;/p&gt;
&lt;h3&gt;Test des librairies&lt;/h3&gt;
&lt;p&gt;Les &amp;quot;librairies&amp;quot; sont le code qu'on place dans le répertoire
&lt;code&gt;lib&lt;/code&gt; de l'application, souvent parce qu'il n'a sa place dans aucun
contrôleur ou modèle et qu'on veut le rendre accessible depuis toute
l'application.&lt;/p&gt;
&lt;p&gt;RoR n'inclut pas les tests des librairies. En réalité, pour créer un tel
test, il suffit de le créer. Le test de &lt;code&gt;lib/my_lib.rb&lt;/code&gt; devrait
logiquement être &lt;code&gt;test/lib/my_lib_test.rb&lt;/code&gt;. RoR aurrait pu faire un
petit quelque chose pour lancer les tests sous &lt;code&gt;test/lib&lt;/code&gt; avec
&lt;code&gt;rake test:libs&lt;/code&gt;, ainsi que lorsqu'on lance les tests avec
&lt;code&gt;rake test&lt;/code&gt;. Qu'à cela ne tienne, un simple ajout dans
&lt;code&gt;lib/tasks&lt;/code&gt; et le tour est joué.&lt;/p&gt;
&lt;h3&gt;Tests des migrations&lt;/h3&gt;
&lt;p&gt;Les migrations sont l'une des bonnes idées de RoR. A vrai dire cela a
probablement existé avant RoR mais leur intégration au framework est réussie.
Une migration est généralement en charge d'une modification &amp;quot;atomique&amp;quot; sur la
base. Typiquement, la création d'une table. Ce peut être également l'ajout de
colonnes à une table existante, l'ajout d'index dont on a réalisé l'importance
après la mise en production... Ce type de modification ne nécessite pas de test
en soit : il suffit d'écrire les tests classiques (unitaires, etc.) qui
tourneront sur la base mise à jour.&lt;/p&gt;
&lt;p&gt;Certaines migrations font en revanche plus que cela. Elles créent une table
pour transformer une relation 1-n en relation n-n, elles modifient une colonne
pour stocker non plus des euros mais des centimes d'euro, etc. Dans de tels
cas, les migrations ne se contentent pas de nouvelles déclarations, elles
itèrent sur les données existantes pour les mettre à jour. Le genre de chose
qu'on voudrait tester avant de se lancer en production. RoR ne permet pas de
tester les migrations. A ma connaissance, il n'existe pas d'extension pour
tester spécifiquement les effets d'une migration.&lt;/p&gt;
&lt;h3&gt;Fixtures véloces&lt;/h3&gt;
&lt;p&gt;Les fixtures de RoR sont décrites en Yaml. C'est simple et efficace. Jusqu'à
ce qu'elles prennent une certaine ampleur. A partir d'un certain point, les
fixtures deviennent délicates à maintenir. Parfois, lorsqu'un test important
exige un cas particulier, on se retrouve à modifier de nombreuses fixtures
ainsi que certains des tests qui reposaient sur elles.&lt;/p&gt;
&lt;p&gt;Des &lt;a href=&quot;http://martincik.com/?p=112&quot;&gt;factories se proposent de
remplacer les fixtures en Yaml&lt;/a&gt;. Celles-ci rendent les données de test plus
dynamiques et proche du code. Reste à en faire bon usage, mais c'est un premier
pas appréciable.&lt;/p&gt;
&lt;h3&gt;Un peu plus de vues ?&lt;/h3&gt;
&lt;p&gt;L'intégration d'un framework de test d'application web haut niveau, comme
&lt;a href=&quot;http://seleniumhq.org/&quot;&gt;Selenium&lt;/a&gt;, serait un plus. Non pas que RoR
ait oublié le test des vues, mais &lt;code&gt;assert_select&lt;/code&gt; ne fait pas tout
et ne remplace pas un rendu dans un véritable navigateur. Certes l'adhérence à
un framework de test spécifique pourrait sembler un peu déplacé de la part de
RoR. Mais ses concepteurs ont déjà franchi le pas, avec succès, dans d'autres
domaines. Par exemple, RoR utilise &lt;a href=&quot;http://www.prototypejs.org/&quot;&gt;Prototype&lt;/a&gt; et &lt;a href=&quot;http://script.aculo.us/&quot;&gt;script.aculo.us&lt;/a&gt;, deux frameworks JavaScript qu'on
est bien content de trouver déjà tout prêt et bien intégrés dans RoR.&lt;/p&gt;
&lt;h2&gt;Avertissement&lt;/h2&gt;
&lt;p&gt;J'ai tenté de dresser un tableau fidèle à la réalité, quoique probablement
incomplet. Cependant, Ruby on Rails est un domaine qui évolue très vite et
possède de nombreuses ramifications. Il est possible que certaines affirmations
soient dépassées. N'hésitez pas à compléter ou rectifier !&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2010/02/28/Le-test-en-Ruby-on-Rails-%3A-forfait%2C-hors-forfait#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2010/02/28/Le-test-en-Ruby-on-Rails-%3A-forfait%2C-hors-forfait#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/490618</wfw:commentRss>
      </item>
    
  <item>
    <title>Deux définitions du test</title>
    <link>http://blog.philippebernard.fr/post/2010/02/06/Deux-d%C3%A9finitions-du-test</link>
    <guid isPermaLink="false">urn:md5:53d516e4174d597c8fbfa9e1ad6ff4ac</guid>
    <pubDate>Sat, 06 Feb 2010 11:53:00 +0100</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
        <category>istqb</category><category>test</category>    
    <description>    &lt;p&gt;Comme tant de domaines, le test logiciel a souvent été défini. On trouvera
une définition différente dans chaque livre, dans chaque glossaire. Avec un peu
de chance, on constatera que ces définitions expriment globalement la même
idée. Est-ce bien le cas ?&lt;/p&gt;
&lt;h2&gt;La définition classique : le test pour vérifier la conformité&lt;/h2&gt;
&lt;p&gt;Le &lt;a href=&quot;http://www.gasq.org/boards/cftl/cms/files/Dokumente/Glossaire%20des%20tests%20de%20logiciel%20-%202%200%20F%20ISTQB.pdf&quot;&gt;
glossaire du CFTL&lt;/a&gt; donne une définition large et conventionnelle du test
logiciel :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Processus consistant en toutes les activités du cycle de vie, statiques et
dynamiques, concernant la planification et l’évaluation de produits logiciels
et produits liés pour déterminer s’ils satisfont aux exigences, pour démontrer
qu’ils sont aptes au objectifs et détecter des anomalies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Voilà une définition qui tache de ne rien oublier : les techniques
statiques, si facilement évincées, l'application à tout le cycle de vie du
logiciel et non aux activités qui précèdent la mise en production... Quant au
but, il est clair : le test permet de vérifier que le logiciel livré et
maintenu est le bon. Celui qui est conforme aux attentes des utilisateurs, aux
besoins, aux exigences, aux standards... Oh, et s'il y a des défauts, ils sont
détectés.&lt;/p&gt;
&lt;p&gt;Cette description est assurément positive. Le test permet d'améliorer la
qualité. Au fait, comment pourrait-il en être autrement ? Contrairement au
développement, le test contribue pas directement au logiciel produit. En
passant commande, le client achète du code (fut-il compilé) et de la
documentation, pas des tests. Par conséquent, le test n'aurait pas sa place
dans les projets s'il n'annonçait pas sa capacité à apporter de la valeur.&lt;/p&gt;
&lt;h2&gt;La définition destructive : le test qui casse le logiciel&lt;/h2&gt;
&lt;p&gt;Dans &lt;a href=&quot;http://www.amazon.com/Art-Software-Testing-Second/dp/0471469122&quot;&gt;The Art of
Software Testing&lt;/a&gt;, Glenford Myers donne une toute autre version :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tester est le processus consistant à exécuter un programme dans le but d'y
trouver des erreurs. *&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;L'approche est radicalement différente. Point de qualité ou de conformité,
mais un but précis et résolument négatif. Trouver des bugs. Mettre en défaut le
travail des développeurs.&lt;/p&gt;
&lt;p&gt;Curieuse approche, voir carrément suicidaire. Entretien d'embauche :
&amp;quot;Bonjour Monsieur l'Employeur. Vous devez savoir que j'aime les bugs. Je les
collectionne.Si vous m'offrez ce poste, je m'évertuerai à démontrer que vos
logiciels sont bourrés d'erreurs&amp;quot;. D'accord, cette approche sarcastique ne dupe
personne. On voit bien que la définition de Myers a du sens. Néanmoins la
question se pose : comment deux définitions si différentes peuvent-elle
coexister ?&lt;/p&gt;
&lt;h2&gt;Une question de buts et de taches&lt;/h2&gt;
&lt;p&gt;Dans le test comme dans la vie, on a des buts :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vérifier la conformité d'un logiciel&lt;/li&gt;
&lt;li&gt;Apprendre le chinois&lt;/li&gt;
&lt;li&gt;Partir en voyage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cet buts permettent de savoir où l'on va. Cependant, ils ne sont pas
réalisables tel quel. Ils ne sont pas &lt;em&gt;actionables&lt;/em&gt; comme le décrit
David Allen dans son best seller &lt;a href=&quot;http://fr.wikipedia.org/wiki/Getting_Things_Done&quot;&gt;Getting Things Done&lt;/a&gt;. On
en peut pas débuter la journée en se disant &amp;quot;Aujourd'hui, j'apprends le
chinois&amp;quot;, car l'apprentissage du chinois prend des années. Pour réaliser ces
buts, il faut :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implémenter les cas de test spécifiés la veille, déclencher une réunion
pour discuter de ces tests qui n'en finissent pas d'échouer, lancer les tests
sur le dernier build...&lt;/li&gt;
&lt;li&gt;Chercher les cours de chinois qui se déroulent dans le quartier, apprendre
10 idéogrammes, regarder un film chinois en VO...&lt;/li&gt;
&lt;li&gt;Renouveler son passeport, rechercher le meilleur rapport qualité/prix sur
Internet, faire la liste des choses à acheter avant le départ...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Autrement dit, on a besoin de décomposer les buts en sous-projets et
finalement en taches qui sont concrètement réalisables. C'est ce que fait la
définition de The Art of Software Testing par rapport à celle du CFTL. Un
testeur ne peut pas poser les mains sur le clavier en pensant &amp;quot;Je vais vérifier
que le logiciel satisfait aux exigences&amp;quot;. Il devrait avoir cela en tête pour ne
pas perdre le Nord, mais cela ne lui dira pas s'il doit lire un document,
ouvrir un fichier ou lancer un test. En approfondissant, le testeur peut
déterminer ses activités :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lire et comprendre les exigences, faire des retours s'il y détecte des
incohérences&lt;/li&gt;
&lt;li&gt;Participer à une revue de code&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L'une de ses activités lui est dictée par la définition de Myers :
exercer le logiciel dans le but d'y trouver des erreurs. A nouveau, le testeur
devra réfléchir aux taches concrètes qui découlent de ce sous-objectif :
écrire un test, exécuter ce test, lire The Art of Software Testing...&lt;/p&gt;
&lt;p&gt;&lt;em&gt;* Testing is the process of executing a program with the intent of
finding errors.&lt;/em&gt;&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2010/02/06/Deux-d%C3%A9finitions-du-test#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2010/02/06/Deux-d%C3%A9finitions-du-test#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/478457</wfw:commentRss>
      </item>
    
  <item>
    <title>Test négatif d'une vérification de signature ou d'un contrôle d'intégrité</title>
    <link>http://blog.philippebernard.fr/post/2010/01/24/Test-n%C3%A9gatif-d-une-v%C3%A9rification-de-signature-ou-d-un-contr%C3%B4le-d-int%C3%A9grit%C3%A9</link>
    <guid isPermaLink="false">urn:md5:6c0351f606604f98020ae108b6a430e6</guid>
    <pubDate>Sun, 24 Jan 2010 12:06:00 +0100</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
            
    <description>    &lt;p&gt;Les signatures jouent un rôle important dans la sécurité des systèmes. Dans
la carte à puce par exemple, la présentation d'une signature permettra de
charger une nouvelle application ou de lire des données sensibles. Les
contrôles d'intégrité ne sont pas en reste. Un problème d'intégrité peut être à
l'origine d'une erreur : un fichier qui ne pourra plus être lu, un
programme qui ne pourra plus être exécuté... Une défaillance dans l'un ou
l'autre de ces domaines peut provoquer une faille de sécurité, une erreur
impardonnable pour un système sensible.&lt;/p&gt;
&lt;h2&gt;Signature et contrôle d'intégrité&lt;/h2&gt;
&lt;p&gt;De quoi parle-t-on ? Pas d'algorithme spécifique. Dans ce post, point
de spécificités de RSA, SHA-1 ou autre. Les signatures et les contrôles ne sont
vus que par ce qu'ils ont en commun : des données à protéger, un
algorithme quelconque et un sceau, qu'il soit authentifiant ou non.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.philippebernard.fr/public/posts/test-negatif-d-une-signature-ou-d-un-controle-d-integrite/algorithme_signature_controle.png&quot;&gt;
&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/test-negatif-d-une-signature-ou-d-un-controle-d-integrite/.algorithme_signature_controle_m.jpg&quot; alt=&quot;Algorithme de signature ou de contrôle d'intégrité&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Algorithme de signature ou de contrôle d'intégrité, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Quel que soit l'algorithme utilisé, le principe même d'une signature ou d'un
contrôle est que le sceau dépend étroitement des données qu'il protège. A deux
données proches mais distinctes correspondent deux sceaux complètement
différents.&lt;/p&gt;
&lt;p&gt;La signature et le contrôle d'intégrité comportent deux phases :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Génération&lt;/strong&gt; : Les données à protéger sont traitées par
l'algorithme et un sceau est généré.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vérification&lt;/strong&gt; : Le système reçoit les données à
vérifier ainsi que le sceau correspondant. Le système régénère le sceau à
partir des données et le compare au sceau qu'il a reçu. S'ils diffèrent, il y a
un problème quelque part... et les données doivent être rejetées.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Comment tester la vérification ?&lt;/p&gt;
&lt;h2&gt;L'importance du test négatif&lt;/h2&gt;
&lt;p&gt;Bien souvent, on attend avant tout d'un système qu'il gère les cas
nominaux :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le système interprète correctement la quantité saisie dans le champ
&amp;quot;Quantité&amp;quot;.&lt;/li&gt;
&lt;li&gt;L'impression d'un document fonctionne convenablement.&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Viennent ensuite les cas d'erreur :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le système affiche un message d'erreur lorsque la quantité saisie est
négative.&lt;/li&gt;
&lt;li&gt;L'option d'impression affiche un message spécial lorsqu'il n'y a pas
d'imprimante.&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce n'est pas que les cas d'erreur ne soient pas importants, mais à choisir,
il vaut mieux qu'on puisse choisir une quantité et imprimer.&lt;/p&gt;
&lt;p&gt;Dans le cas d'une vérification d'intégrité ou de signature, le cas d'erreur
est aussi important que le cas nominal :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cas nominal&lt;/strong&gt; : Le système vérifie des données valides.
Si cette vérification ne fonctionne pas (dans le sens où elle est buggée), le
système va déclarer de faux négatifs, c'est à dire qu'il va rejeter des données
pourtant valides. Un problème à ce niveau est bloquant : il y a de bonnes
chances pour que rien ne fonctionne, puisque la vérification d'intégrité ou
d'authenticité est souvent un préalable à tout autre traitement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cas d'erreur&lt;/strong&gt; : Le système vérifie des données
invalides. Si la vérification est buggée à ce niveau, le système va déclarer
des faux positifs, en acceptant des données corrompues comme si elles étaient
valides. Dans cette situation, la vérification échoue dans sa mission de
détecter les erreurs. Plus que cela, c'est certainement tout le système qui est
compromis, spécialement dans le cas d'une signature. Pour moi qui exerce dans
le domaine des cartes à puce, c'est l'un des bugs les plus graves qui puisse
survenir.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;De plus, le cas nominal est généralement testé par effet de bord. Si le
système exige une authentification avant toute autre action, alors la majorité
des tests enverront des signatures correctes de sorte à atteindre &amp;quot;l'étape
suivante&amp;quot;. Pas de seconde chance en revanche pour le cas négatif : rien de
viendra remplacer un test explicite.&lt;/p&gt;
&lt;h2&gt;Assurer que la vérification est faite&lt;/h2&gt;
&lt;p&gt;Le bug de vérification le plus grossier est... l'absence de vérification.
Aussi gros que ce bug puisse être, il est assez plausible :&lt;/p&gt;
&lt;pre&gt;
...
dataToProcess = receiveData();
// TODO: restaurer cette ligne quand l'authentification
// marchera !
//if (!authenticate(dataToProcess)) {
//  throw Exception(&amp;quot;Authentication failed!&amp;quot;);
//}
processData(dataToProcess);
...
&lt;/pre&gt;
&lt;p&gt;Ou carrément :&lt;/p&gt;
&lt;pre&gt;
...
dataToProcess = receiveData();
processData(dataToProcess);
...
&lt;/pre&gt;
&lt;p&gt;(il n'y a rien à voir : l'authentification a été purement et simplement
oubliée)&lt;/p&gt;
&lt;p&gt;Non seulement le bug est possible, mais il peut tout à fait passer inaperçu.
La vérification d'intégrité ou d'authenticité fait partie de ces
fonctionnalités qui ne se manifestent normalement pas, sauf en cas de problème.
De ce fait on peut tout à fait passer à côté de ce bug critique.&lt;/p&gt;
&lt;p&gt;En soit, tester la vérification est simple. Il suffit d'envoyer un mauvais
sceau au système :&lt;/p&gt;
&lt;pre&gt;
data = {1, 2, 3};
seal = generateCorrectSeal(data);
// Ce sceau est correct et accepté par le système
assertTrue(verifySeal(data, seal));
// On corrompt le sceau en inversant tous les bits
for (int i = 0; i &amp;lt; seal.length; i++) {
  seal[i] = seal[i] ^ 0xFF;
}
// Ce sceau corrompu devrait être rejeté
assertFalse(verifySeal(data, seal));
&lt;/pre&gt;
&lt;p&gt;Ce test fait l'affaire. Mais attention à ne pas &lt;a href=&quot;http://blog.philippebernard.fr/post/2009/12/03/Le-test-qui-ne-pouvait-%C3%A9chouer&quot;&gt;écrire un test
faux&lt;/a&gt; !&lt;/p&gt;
&lt;p&gt;Dans cet exemple, le test est écrit comme un test unitaire, qui cible un
point d'entrée du système, &lt;code&gt;verifySeal&lt;/code&gt;. En réalité, ce test est
typiquement un candidat pour les tests système. Afin d'éviter le bug de la
vérification qui n'est pas faite, on doit faire l'essai sur le système entier
et non sur une de ses parties, qui peut justement être présente mais
non-sollicitée.&lt;/p&gt;
&lt;h2&gt;Assurer que la vérification est complète&lt;/h2&gt;
&lt;p&gt;Un second bug peut affecter la vérification : elle peut être
incomplète. Par exemple :&lt;/p&gt;
&lt;pre&gt;
public boolean verifySeal(data, seal) {
  expecedSeal = generateSeal(data);
  // Le sceau est un hash SHA-1
  return compare(expectedSeal, seal, 16);
}
&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;verifySeal&lt;/code&gt; génère le sceau qui devrait normalement accompagner
les données et le compare au sceau reçu. Le bug se situe dans la longueur de la
comparaison. Si le sceau est le résultat d'un hash SHA-1, alors sa longueur est
de 20 octets et non 16. La conséquence : les 4 derniers octets du sceau ne
sont pas contrôlés. Cela affaiblit la vérification. Dans le cas d'une
signature, le bug facilite une attaque force brute.&lt;/p&gt;
&lt;p&gt;Le test :&lt;/p&gt;
&lt;pre&gt;
data = {1, 2, 3};
seal = generateCorrectSeal(data);
// Ce sceau est correct et accepté par le système
assertTrue(verifySeal(data, seal));
// On corrompt chaque octet du sceau
for (int i = 0; i &amp;lt; 20; i++) {
  // On corrompt chaque bit de l'octet
  for (int bit = 0; bit &amp;lt; 8; bit++) {
    // On inverse le bit testé
    seal[i] = seal[i] ^ (1 &amp;lt;&amp;lt; bit);
    // Ce sceau corrompu devrait être rejeté
    assertFalse(verifySeal(data, seal));
    // On restaure le bit testé
    seal[i] = seal[i] ^ (1 &amp;lt;&amp;lt; bit);
  }
}
// Afin de d'éviter un bug de test, on vérifie qu'en
// fin de test seal contient à nouveau le sceau
// attendu
assertTrue(verifySeal(data, seal));
&lt;/pre&gt;
&lt;h2&gt;Assurer que toutes les données sont vérifiées&lt;/h2&gt;
&lt;p&gt;La vérification peut être incomplète en ne portant que sur une partie du
sceau. On peut imaginer une bug similaire sur les données elles-même. Il suffit
d'une erreur de bornes pour qu'une partie des données ne soient pas impliquées
dans la génération du sceau.&lt;/p&gt;
&lt;p&gt;Un tel bug sera détecté sans qu'un test spécifique soit nécessaire. D'un
côté, un test prouve déjà que la vérification est effectuée. De l'autre, il y a
forcément de nombreux cas positifs engendrés par d'autres tests qui veulent
simplement &amp;quot;passer&amp;quot; la phase de vérification pour atteindre d'autres
fonctionnalités du système. La combinaison de ces deux éléments permettent de
s'assurer que les sceaux sont correctement calculés par le système. La nature
de ces sceaux, qu'ils soient CRC, hash ou signatures, fait qu'on sait que
toutes les données sont prises en compte dans la vérification : si,
disons, le dernier octet des données était systématiquement ignoré, le sceau
généré serait très différent de celui attendu et généré par les tests.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2010/01/24/Test-n%C3%A9gatif-d-une-v%C3%A9rification-de-signature-ou-d-un-contr%C3%B4le-d-int%C3%A9grit%C3%A9#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2010/01/24/Test-n%C3%A9gatif-d-une-v%C3%A9rification-de-signature-ou-d-un-contr%C3%B4le-d-int%C3%A9grit%C3%A9#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/478351</wfw:commentRss>
      </item>
    
  <item>
    <title>Tutoriel Selenium</title>
    <link>http://blog.philippebernard.fr/post/2010/01/10/Tutoriel-Selenium</link>
    <guid isPermaLink="false">urn:md5:2af2677f61651d501f925fbaa3af2be3</guid>
    <pubDate>Sun, 10 Jan 2010 19:24:00 +0100</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
        <category>Tutoriels</category>
        <category>outil</category><category>selenium</category><category>test</category><category>tutoriel</category><category>web</category>    
    <description>    &lt;p&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/logo-selenium.png&quot; alt=&quot;Logo Selenium&quot; style=&quot;float:left; margin: 0 1em 1em 0;&quot; title=&quot;Logo Selenium, janv. 2010&quot; /&gt; &lt;a href=&quot;http://seleniumhq.org/&quot;&gt;SeleniumHQ&lt;/a&gt;
est un outil de test pour les applications Web. Il permet de vérifier qu'une
application se comportera de la même façon quel que soit le navigateur utilisé.
Selenium s'utilise ainsi :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Enregistrement d'une séquence&lt;/strong&gt; : A l'aide d'un plugin
Firefox, on enregistre une séquence. Clic sur un lien, saisi d'un formulaire,
vérification d'une réponse...&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Intégration du test&lt;/strong&gt; : On intègre le test au sein
d'une suite de test, dans le langage et le framework de son choix.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exécution du test&lt;/strong&gt; : Le test est joué sur plusieurs
navigateurs et plusieurs plateformes afin de valider l'interopérabilité de
l'application.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Selenium est indépendant du langage utilisé. On peut tester une application
PHP, Java, Ruby on Rails... De plus, Selenium supporte les langages les plus
communs pour la programmation Web :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C#&lt;/li&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;Perl&lt;/li&gt;
&lt;li&gt;PHP&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En plus des langages, Selenium connait les frameworks les plus utilisés. Par
exemple, en Ruby on Rails, on pourra générer des tests Test::Unit ou RSpec, au
choix. De cette façon, on obtient des tests consistants avec le reste des tests
écrits pour l'application.&lt;/p&gt;
&lt;p&gt;Dans ce tutoriel, plutôt que de développer une application pour l'occasion,
nous allons tester une application existante : le moteur de recherche de
Google (un exemple très inspiré, d'autant que c'est aussi l'exemple choisi par
les développeurs de Selenium). Nous allons générer un test JUnit que nous
allons intégrer au sein d'une suite de test, puis nous exécuterons ce test.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;Nous allons avoir besoin de Selenium IDE :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Lancez Firefox&lt;/li&gt;
&lt;li&gt;Allez sur la &lt;a href=&quot;http://seleniumhq.org/download/&quot;&gt;page de
téléchargement de Selenium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sélectionnez le téléchargement de Selenium IDE &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/page_de_telechargement.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.page_de_telechargement_m.jpg&quot; alt=&quot;Page de téléchargement&quot; title=&quot;Page de téléchargement, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Le téléchargement fait apparaitre un bandeau &lt;em&gt;Firefox a empêché ce site
(seleniumhq.org) d'installer un logiciel sur votre ordinateur&lt;/em&gt; en haut de
la page. Cliquez sur &lt;em&gt;Autoriser&lt;/em&gt; pour permettre l'installation. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/installation_bloquee.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.installation_bloquee_m.jpg&quot; alt=&quot;Installation bloquée&quot; title=&quot;Installation bloquée, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dans le popup &lt;em&gt;Installation d'un logiciel&lt;/em&gt;, cliquez sur
&lt;em&gt;Installer maintenant&lt;/em&gt;. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/installation_plugin.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.installation_plugin_m.jpg&quot; alt=&quot;Installation d'un logiciel&quot; title=&quot;Installation d'un logiciel, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dans le popup &lt;em&gt;Modules complémentaires&lt;/em&gt;, cliquez sur &lt;em&gt;Redémarrer
Firefox&lt;/em&gt; pour terminer l'installation. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/modules_complementaires.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.modules_complementaires_m.jpg&quot; alt=&quot;Modules complémentaires&quot; title=&quot;Modules complémentaires, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nous allons aussi utiliser Selenium RC pour exécuter le test :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Allez sur la &lt;a href=&quot;http://seleniumhq.org/download/&quot;&gt;page de
téléchargement de Selenium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Téléchargez Selenium RC &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/download_selenium_rc.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.download_selenium_rc_m.jpg&quot; alt=&quot;Téléchargement de Selenium RC&quot; title=&quot;Téléchargement de Selenium RC, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Décompressez l'archive téléchargée dans le répertoire de votre choix. Par
exemple, dans &lt;code&gt;C:\Program Files (x86)&lt;/code&gt; (auquel cas Selenium RC est
installé dans &lt;code&gt;C:\Program Files
(x86)\selenium-remote-control-1.0.1&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Puisque nous allons utiliser JUnit, nous l'installons également :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Allez sur la &lt;a href=&quot;http://sourceforge.net/projects/junit/files/junit/&quot;&gt;page de téléchargement de
JUnit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Téléchargez le JAR de JUnit &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/download_junit.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.download_junit_m.jpg&quot; alt=&quot;Téléchargement de JUnit&quot; title=&quot;Téléchargement de JUnit, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Copiez le JAR de JUnit tel quel dans le répertoire de votre choix (il ne
faut pas le décompresser). Par exemple, dans &lt;code&gt;C:\Program Files
(x86)\junit-4-8-1&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Enregistrement&lt;/h2&gt;
&lt;p&gt;L'installation terminée, nous pouvons créer notre premier test. La première
étape consiste à enregistrer la séquence que nous voulons automatiser.&lt;/p&gt;
&lt;p&gt;Dans cet exemple, nous testons le moteur de recherche de Google et écrivons
un test qui s'assure que le site de Selenium (&lt;a href=&quot;http://seleniumhq.org/&quot;&gt;seleniumhq.org&lt;/a&gt;) fait partie des résultats de la
première page lorsqu'on lance une recherche Google sur &amp;quot;selenium&amp;quot;. L'objet de
ce test est évidemment discutable : si le site de Selenium n'apparait pas
sur la première page, cela peut être dû à un mauvais référencement de ce
dernier, plutôt qu'à un authentique bug de Google. Dans le cadre de ce
tutoriel, c'est bien suffisant.&lt;/p&gt;
&lt;p&gt;Pour enregistrer la séquence :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Lancez Firefox&lt;/li&gt;
&lt;li&gt;Allez sur la &lt;a href=&quot;http://www.google.fr/&quot;&gt;page d'accueil de
Google&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lancez Selenium IDE à partir de Firefox, dans le menu &lt;em&gt;Outils&lt;/em&gt;
&lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/start_ide.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.start_ide_s.jpg&quot; alt=&quot;Lancement de Selenium IDE&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Lancement de Selenium IDE, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Disposez Firefox et Selenium IDE de sorte à voir les deux fenêtres
simultanément. Cela n'a rien d'obligatoire, mais il est pratique de voir la
fenêtre de Selenium mise à jour au fur et à mesure de l'enregistrement du
test.&lt;/li&gt;
&lt;li&gt;Saisissez l'URL de la page d'accueil de Google dans le champ &lt;em&gt;Base
URL&lt;/em&gt; de Selenium IDE. En effet, cette page sera le point de départ de notre
test. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/ide_layout.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.ide_layout_m.jpg&quot; alt=&quot;Disposition Selenium IDE / Firefox&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Disposition Selenium IDE / Firefox, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lancez l'enregistrement en cliquant sur le bouton &lt;em&gt;Record&lt;/em&gt; de
Selenium IDE. Selenium est maintenant en train d'enregistrer les actions de
l'utilisateur dans Firefox : click, saisie... &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/start_record.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.start_record_s.jpg&quot; alt=&quot;Lancement de l'enregistrement&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Lancement de l'enregistrement, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Jouez la séquence à enregistrer. Saisissez &amp;quot;selenium&amp;quot; dans la page de
Google et cliquez sur &lt;em&gt;Recherche Google&lt;/em&gt;. On constate que Selenium IDE
liste les actions au fur et à mesure. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/record_sequence.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.record_sequence_s.jpg&quot; alt=&quot;Exécution de la séquence&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Exécution de la séquence, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ajoutez une assertion. Dans la page de résultat de Google, nous voulons
nous assurer qu'un lien vers le site de Selenium est présent. Il apparait
effectivement, on peut voir le texte &amp;quot;seleniumhq.org&amp;quot; qui apparait au bas du
premier résultat. Sélectionnez ce texte dans Firefox, faites un clic droit et
sélectionnez &lt;em&gt;verifyTextPresent seleniumhq.org&lt;/em&gt; &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/add_assertion.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.add_assertion_s.jpg&quot; alt=&quot;Ajout d'assertion&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Ajout d'assertion, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Stoppez l'enregistrement. Dans la fenêtre de Selenium IDE, cliquez de
nouveau sur le bouton &lt;em&gt;Record&lt;/em&gt; pour arrêter l'enregistrement. On
constate que Selenium a enregistré la séquence que nous venons de jouer :
&lt;code&gt;open /&lt;/code&gt; ouvre la page de Google, &lt;code&gt;type q selenium&lt;/code&gt;
saisit &amp;quot;selenium&amp;quot; dans le champ texte de la page d'accueil de Google,
&lt;code&gt;clickAndWait btnG&lt;/code&gt; clique sur le bouton &lt;em&gt;Recherche Google&lt;/em&gt;
et attend la page de résultat et &lt;code&gt;verifyTextPresent seleniumhq.org&lt;/code&gt;
s'assure que le texte &amp;quot;seleniumhq.org&amp;quot; est bien présent dans la page de
résultat. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/stop_record.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.stop_record_s.jpg&quot; alt=&quot;Arrêt de l'enregistrement&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Arrêt de l'enregistrement, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rejouez le test. Maintenant que Selenium a enregistré la séquence, nous
pouvons la rejouer à loisir. Cliquez sur le bouton &lt;em&gt;Play entire test
suite&lt;/em&gt;. Selenium IDE joue le test &amp;quot;pour de vrai&amp;quot; en pilotant Firefox. On
voit ce dernier aller sur la page d'accueil de Google, saisir &amp;quot;selenium&amp;quot; et
charger la page de résultat. Selenium IDE liste ce qu'il a exécuté dans
l'onglet &lt;em&gt;Log&lt;/em&gt;. On constate que l'assertion finale est également
évaluée : si &amp;quot;seleniumhq.org&amp;quot; n'apparaissait pas dans la page de
recherche, Selenium le signalerait et le test échouerait. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/run_test.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.run_test_s.jpg&quot; alt=&quot;Exécution du test&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;Exécution du test, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Intégration&lt;/h2&gt;
&lt;p&gt;Pour le moment, nous avons un test que nous pouvons jouer à partir d'une
interface graphique. C'est un début, mais il faut aller plus loin :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Exécution dans d'autres navigateurs&lt;/strong&gt; : Développer avec
Firefox pourquoi pas, mais il faut s'assurer que l'application fonctionne aussi
avec Internet Explorer, Safari et les autres.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gérer de nombreux tests&lt;/strong&gt; : Dans ce tutoriel, on se
contente d'un test. Dans un cas réel, on a plusieurs dizaines, centaines voir
milliers de tests. Cette interface graphique n'est pas viable pour un tel
usage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tests intégrés&lt;/strong&gt; : Jouer le test à partir de
l'interface graphique est pratique lorsqu'on le met au point. En revanche, cela
n'est plus praticable lorsqu'on veut jouer le test au même titre que les autres
tests de l'application (tests unitaires, etc.). Les tests générés avec Selenium
doivent pouvoir être lancés dans le cadre d'une intégration continue, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modification et déclinaison du test&lt;/strong&gt; : Nous pourrions
souhaiter décliner notre test de plusieurs façons. Par exemple, en recherchant
différents termes. Avec Selenium IDE, notre seule option est de jouer le
scénario encore et encore pour créer nos tests. Cela va vite devenir
ennuyeux.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L'étape d'intégration est très rapide car Selenium génère directement un
test JUnit pour nous :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Dans Selenium IDE, sélectionnez &lt;em&gt;Options &amp;gt; Format &amp;gt; Java
(JUnit)&lt;/em&gt;. Selenium affiche alors notre test au format JUnit. On reconnait
les dfférentes étapes, mais &amp;quot;à la Java&amp;quot; : &lt;code&gt;selenium.open(&amp;quot;/&amp;quot;)&lt;/code&gt;
pour ouvrir la page d'acueil de Google, etc. &lt;a href=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/select_format.png&quot;&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/posts/tutoriel_selenium/.select_format_m.jpg&quot; alt=&quot;Sélection du format&quot; title=&quot;Sélection du format, janv. 2010&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Copiez le contenu du test, collez-le dans un fichier
&lt;code&gt;SearchTest.java&lt;/code&gt; que vous créez n'importe où.&lt;/li&gt;
&lt;li&gt;Supprimez la mention du package. Dans &lt;code&gt;Search.java&lt;/code&gt;, supprimez
la ligne de déclaration du package (&lt;code&gt;package com.example.tests;&lt;/code&gt;).
Dans un cas réel, nous devrions spécifier un package relatif à l'entité pour
laquelle nous développons. Dans le cadre de cet exemple, nous allons au plus
simple.&lt;/li&gt;
&lt;li&gt;Changer le nom de la classe pour &lt;code&gt;SearchTest&lt;/code&gt;. Autrement dit,
&lt;code&gt;public class Untitled&lt;/code&gt; devient &lt;code&gt;public class
SearchTest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Changer le nom de la méthode de test pour &lt;code&gt;testSearch&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Le test définitif :&lt;/p&gt;
&lt;pre&gt;
import com.thoughtworks.selenium.*;
import java.util.regex.Pattern;

public class SearchTest extends SeleneseTestCase {
  public void setUp() throws Exception {
    setUp(&amp;quot;http://www.google.fr/&amp;quot;, &amp;quot;*chrome&amp;quot;);
  }
  public void testSearch () throws Exception {
    selenium.open(&amp;quot;/&amp;quot;);
    selenium.type(&amp;quot;q&amp;quot;, &amp;quot;selenium&amp;quot;);
    selenium.click(&amp;quot;btnG&amp;quot;);
    selenium.waitForPageToLoad(&amp;quot;30000&amp;quot;);
    verifyTrue(selenium.isTextPresent(&amp;quot;seleniumhq.org&amp;quot;));
  }
}
&lt;/pre&gt;
&lt;p&gt;A présent nous compilons ce test. La séquence qui suit est pour Windows. Si
vous utilisez un autre environnement, vous devrez adapter certaines
commandes :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ouvrez une console. Faites &lt;em&gt;Touche Windows + R&lt;/em&gt;, puis demandez à
lancer le programme &lt;code&gt;cmd&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Définissez l'emplacement de Selenium RC en définissant la variable
&lt;code&gt;SELENIUM_RC_HOME&lt;/code&gt;. Par exemple, &lt;code&gt;set
SELENIUM_RC_HOME=C:\Program Files
(x86)\selenium-remote-control-1.0.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Définissez l'emplacement de JUnit en définissant la variable
&lt;code&gt;JUNIT_HOME&lt;/code&gt;. Par exemple, &lt;code&gt;set JUNIT_HOME=C:\Program Files
(x86)\JUnit-4-8-1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Placez-vous dans le répertoire où vous avez créé
&lt;code&gt;SearchTest.java&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Compilez le test avec la commande &lt;code&gt;javac -cp
&amp;quot;%JUNIT_HOME%\junit-4.8.1.jar;%SELENIUM_RC_HOME%\selenium-java-client-driver-1.0.1\selenium-java-client-driver.jar&amp;quot;
SearchTest.java&lt;/code&gt;. Vous devrez peut-être adapter cette commande si vous
avez téléchargé une version plus récente de JUnit ou Selenium RC.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Le test est désormais intégré aux autres tests unitaires de l'application.
De plus, comme il s'agit de véritable code et non d'une séquence figée, nous
pouvons modifier le test pour jouer la séquence plusieurs fois, par exemple
avec différents termes de recherche.&lt;/p&gt;
&lt;h2&gt;Exécution&lt;/h2&gt;
&lt;p&gt;Maintenant que nous avons un test compilé, nous pouvons l'excuter. Dans ce
post, nous ne verrons qu'une façon de le lancer. Cependant, il existe plusieurs
options, selon ce que nous attendons de nos tests.&lt;/p&gt;
&lt;h3&gt;Exécution simple&lt;/h3&gt;
&lt;p&gt;C'est le mode par défaut, celui qu'utilisent les développeurs pour vérifier
leurs réalisations. Le test est lancé depuis la ligne de commande ou depuis un
IDE et le résultat est utilisé sur le champ : si bug il y a, il est
fixé !&lt;/p&gt;
&lt;p&gt;Lorqu'on exécute un test avec Selenium, celui-ci est joué dans un véritable
navigateur Web, et non par envoi direct de requêtes HTTP, par exemple. Pour
réaliser cela, Selenium utilise un serveur. Ce serveur reçoit les requêtes du
test (&amp;quot;ouvrir une page&amp;quot;, &amp;quot;cliquer&amp;quot;, etc.) et ouvre un navigateur qu'il pilote
pour exécuter les commandes du test. Par conséquent, pour lancer
&lt;code&gt;SearchTest&lt;/code&gt;, nous devons d'abord lancer le serveur
Selenium :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ouvrez une nouvelle console.&lt;/li&gt;
&lt;li&gt;Définissez l'emplacement de Selenium RC en définissant la variable
&lt;code&gt;SELENIUM_RC_HOME&lt;/code&gt;. Par exemple, &lt;code&gt;set
SELENIUM_RC_HOME=C:\Program Files
(x86)\selenium-remote-control-1.0.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Ajouter Firefox dans votre &lt;code&gt;PATH&lt;/code&gt;. Par exemple, si Firefox est
installé dans &lt;code&gt;C:\Program Files (x86)\Mozilla Firefox&lt;/code&gt;, utilisez
&lt;code&gt;set PATH=%PATH%;C:\Program Files (x86)\Mozilla Firefox&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Lancez le server Selnium avec la commande &lt;code&gt;java -jar
&amp;quot;%SELENIUM_RC_HOME%\selenium-server-1.0.1\selenium-server.jar&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nous sommes maintenant prêts à lancer le test :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reprenez la console que vous avez utilisée pour compiler le test, celle où
&lt;code&gt;JUNIT_HOME&lt;/code&gt; et &lt;code&gt;SELENIUM_RC_HOME&lt;/code&gt; sont définies et pour
laquelle le répertoire courant contient le test compilé.&lt;/li&gt;
&lt;li&gt;Lancez le test avec la commande &lt;code&gt;java -classpath
&amp;quot;%JUNIT_HOME%\junit-4.8.1.jar;%SELENIUM_RC_HOME%\selenium-java-client-driver-1.0.1\selenium-java-client-driver.jar;.&amp;quot;
junit.textui.TestRunner SearchTest&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A l'exécution de cette dernière commande, Selenium RC lance une instance de
Firefox et on peut voir le test se dérouler. Cela étant dit, ce n'est pas de
voir le navigateur qui nous importe, mais le résultat : à la fin de
l'exécution, &lt;code&gt;SearchTest&lt;/code&gt; est passed, comme tout test JUnit exécuté
avec succès. Il n'y a pas d'intervention manuelle.&lt;/p&gt;
&lt;h3&gt;Validation, Régression, Intégration continue...&lt;/h3&gt;
&lt;p&gt;Au delà de l'exécution simple, Selenium permet d'exécuter des tests
automatisés à toutes les étapes de la vie du projet :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Intégration Continue&lt;/strong&gt;. Ces tests sont de parfaits condidats
pour une exécution fréquente et programmée : toutes les nuits, toutes les
semaines...&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test de Régression&lt;/strong&gt;. Comme ils sont automatisés, ces tests
peuvent être utilisés par les développeurs comme tests de régression, jouables
facilement et rapidement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test de validation&lt;/strong&gt;. Naturellement, on peut se servir de
ces tests pour valider l'application avant livraison. Une fois encore,
l'automatisation fait qu'on ne devrait pas se priver de les jouer.&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Test d'interopérabilité&lt;/h3&gt;
&lt;p&gt;Une particularité de Selenium est de lancer les tests sur un véritable
navigateur. Comme celui-ci est capable de gérer les principaux navigateurs et
qu'il peut s'exécuter sur les principales plateformes, il est l'outil idéal
pour vérifier l'interopérabilité de l'application : &amp;quot;Si mon test passe
avec succès à partir de Firefox exécuté sous Windows, le fera-t-il avec Safari
exécuté sous Mac ?&amp;quot; Selenium permet de répondre à cette question, une fois de
plus de façon automatisée.&lt;/p&gt;
&lt;p&gt;Le test d'interopérabilité peut être &amp;quot;fait maison&amp;quot; : on se procure
machines et navigateurs, on lance différents serveurs Selenium et le tour est
joué. Cela demande toutefois pas mal d'efforts : gestion de plateformes
différentes, gestion des ressources (deux testeurs ne doivent pas utiliser le
même serveur en même temps)... Des entreprises fournissent des &lt;a href=&quot;http://www.apidev.fr/blog/2009/12/01/cloud-testing-5-solutions-pour-tester-un-site-internet/&quot;&gt;
solutions de test à la demande&lt;/a&gt; pour éviter ces problèmes.&lt;/p&gt;
&lt;h3&gt;Test de charge&lt;/h3&gt;
&lt;p&gt;Les tests Selenium peuvent servir de base au test de charge. Au lieu de
jouer un test à la fois, on en exécute... un grand nombre ! Comme pour le
test d'interopérabilité, ce principe nécessite une certaine organisation pour
être mis en œuvre.&lt;/p&gt;
&lt;p&gt;Selenium est un outil puissant, élégant et facile à prendre en main.
L'essayer c'est l'adopter ! Faites l'essai !&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2010/01/10/Tutoriel-Selenium#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2010/01/10/Tutoriel-Selenium#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/470754</wfw:commentRss>
      </item>
    
  <item>
    <title>Données de test : Attention aux pièges !</title>
    <link>http://blog.philippebernard.fr/post/2009/12/24/Donn%C3%A9es-de-test-%3A-Attention-aux-pi%C3%A8ges-%21</link>
    <guid isPermaLink="false">urn:md5:215d17aa35ca2686e653edc6732ac671</guid>
    <pubDate>Thu, 24 Dec 2009 12:20:00 +0100</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
        <category>technique de test</category><category>test</category>    
    <description>    &lt;p&gt;Lorsqu'on teste, on a souvent besoin de données factices. Dans ce post, ce
que j'appelle &amp;quot;données factices&amp;quot; sont des octets quelconques, sans sens
particulier. Dans un certain nombre de cas, le contenu n'a pas d'importance,
comme dans l'exemple suivant :&lt;/p&gt;
&lt;pre&gt;
// Testons les fonctions write(file, dataToWrite) et 
// read(file, outputBuffer) 
// On devrait pouvoir lire ce qu'on vient d'écrire
// dans FILE_1
testData = { ??? }
write(FILE_1, testData)
read(FILE_1, readData)
// Vérification que testData et readData
// contiennent la même chose
assertEquals(testData, readData)
&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;read&lt;/code&gt; et &lt;code&gt;write&lt;/code&gt; ne se préoccupent pas des données
qu'elle manipulent. Ce cas de test fonctionne quel que soit la valeur de
&lt;code&gt;testData&lt;/code&gt;. Est-ce que cela signifie qu'on prendre n'importe
quoi ? Certainement pas.&lt;/p&gt;
&lt;h2&gt;Remplissage avec des zéros&lt;/h2&gt;
&lt;pre&gt;
testData = {0, 0, 0, ... }
&lt;/pre&gt;
&lt;p&gt;Le remplissage avec des zéros est le comportement par défaut dans un certain
nombre de langages. Par exemple, en Java :&lt;/p&gt;
&lt;pre&gt;
testData = new byte[10];
// testData vaut {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
&lt;/pre&gt;
&lt;p&gt;On peut utiliser n'importe quel contenu pour ce test, alors pourquoi
s'embêter ? Pour répondre à cette question, reformulons le problème.
&lt;code&gt;read&lt;/code&gt; et &lt;code&gt;write&lt;/code&gt; peuvent être bugguées. Nous avons un
test pour ça. Le seul élément qui nous manque est &lt;code&gt;testData&lt;/code&gt;. La
question devient :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Y a-t-il un bug potentiel qui pourrait échapper à notre test en raison du
choix de &lt;code&gt;testData&lt;/code&gt; ?&lt;/li&gt;
&lt;li&gt;Quelle est la probabilité de ce bug ?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On pourrait imaginer plusieurs implémentations. Celle-ci est
suffisante :&lt;/p&gt;
&lt;pre&gt;
write(file, dataToWrite) {
  // TODO
}

read(file, outputBuffer) {
  // TODO
}
&lt;/pre&gt;
&lt;p&gt;En fait... &lt;code&gt;read&lt;/code&gt; et &lt;code&gt;write&lt;/code&gt; ne sont pas implémentées.
Elles ne font rien et attendent qu'un développeur bienveillant les code. Si le
produit est livré en l'état, on peut s'attendre à un bug à moment ou à un
autre !&lt;/p&gt;
&lt;p&gt;Évidemment, notre test devrait repérer cette erreur grossière. Que se
passe-t-il si on l'exécute ? Rien. Il s'achève en un &amp;quot;PASSED&amp;quot; tout à fait
rassurant. &lt;code&gt;testData&lt;/code&gt; est rempli avec des zéros et il en est de même
pour &lt;code&gt;readData&lt;/code&gt; dans un langage comme Java si on ne prend pas la
précaution de l'initialiser (et pourquoi le ferait-on ? &lt;code&gt;read&lt;/code&gt;
est supposé l'écrire après tout). Par conséquent, l'assertion finale compare
deux tableaux identiques (&lt;code&gt;{0, 0, ...}&lt;/code&gt;) et passe.&lt;/p&gt;
&lt;p&gt;Le pattern &amp;quot;zero&amp;quot; est vraiment, vraiment mauvais. Au suivant !&lt;/p&gt;
&lt;h2&gt;Remplissage avec une unique valeur&lt;/h2&gt;
&lt;pre&gt;
testData = {0x95, 0x95, 0x95, ... }
&lt;/pre&gt;
&lt;p&gt;Le zéro était une mauvaise idée. Qu'en est-il d'une autre valeur ? Même
approche, voici le bug :&lt;/p&gt;
&lt;pre&gt;
write(file, dataToWrite) {
  // TODO
}

read(file, outputBuffer) {
  fill(outputBuffer, 0x95)
}
&lt;/pre&gt;
&lt;p&gt;A nouveau, le bug est facile à obtenir : &lt;code&gt;write&lt;/code&gt; ne fait
rien et &lt;code&gt;read&lt;/code&gt; remplit le buffer avec &lt;code&gt;0x95&lt;/code&gt;, peu importe
ce qu'on lui demande. Cependant, la situation est bien différente de l'exemple
précédent. Oublier d'implémenter deux fonctions est une erreur tout à fait
plausible. Mais que penser de &lt;code&gt;fill(outputBuffer, 0x95)&lt;/code&gt; dans la
seconde version ? Cette instruction est étrange. C'est plus qu'un oubli ou
une incompréhension du développeur. L'hypothèse du programmeur compétent dit
que cette erreur est peu probable.&lt;/p&gt;
&lt;p&gt;Bien, une valeur non-nulle est meilleure que zéro, mais est-elle bonne pour
autant ? Non, toujours pas :&lt;/p&gt;
&lt;pre&gt;
write(file, dataToWrite) {
  for i = 0... dataToWrite.length - 1 {
    internalBuffer[file][i] = dataToWrite[0]
  }
}

read(file, outputBuffer) {
  for i = 0... dataToWrite.length - 1 {
    outputBuffer[i] = internalBuffer[file][i]
  }
}
&lt;/pre&gt;
&lt;p&gt;Cette fois-ci, &lt;code&gt;read&lt;/code&gt; et &lt;code&gt;write&lt;/code&gt; font quelque chose de
sensé. &lt;code&gt;write&lt;/code&gt; copie les données dans un buffer interne et
&lt;code&gt;read&lt;/code&gt; fait l'opération inverse. Mais une fois encore, il y a un
bug, tout à fait plausible cette fois-ci : au lieu de prendre l'octet à
l'offset &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;write&lt;/code&gt; copie toujours le premier octet de
&lt;code&gt;dataToWrite&lt;/code&gt;. Et comme tous les octets de &lt;code&gt;dataToWrite&lt;/code&gt;
sont identiques dans notre test, le bug ne sera pas découvert.&lt;/p&gt;
&lt;p&gt;Le pattern basé sur une répétition est un mauvais choix pour une situation
type &amp;quot;système de fichier&amp;quot; comme celle-ci. En plaçant tous les octets sur un
plan d'égalité, il tend à annuler les nombreuses erreurs d'offset et longueur
qui peuvent se produire.&lt;/p&gt;
&lt;h2&gt;Valeur = Index&lt;/h2&gt;
&lt;pre&gt;
testData = {0, 1, 2, ... }
&lt;/pre&gt;
&lt;p&gt;Utiliser une seule valeur n'est pas efficace. L'étape suivante est
d'utiliser plusieurs valeurs. Un tableau du type &lt;code&gt;{0, 1, 2, ... }&lt;/code&gt;
pourrait être un bon candidat. Il a l'avantage d'être facile à
construire :&lt;/p&gt;
&lt;pre&gt;
for i = 0... testData.length - 1 {
  testData[i] = i
}
&lt;/pre&gt;
&lt;p&gt;Et... voici le bug :&lt;/p&gt;
&lt;pre&gt;
write(file, dataToWrite) {
  for i = 0... dataToWrite.length - 1 {
    internalBuffer[file][i] = dataToWrite[i]
  }
}

read(file, outputBuffer) {
  for i = 0... dataToWrite.length - 1 {
    outputBuffer[i] = i
  }
}
&lt;/pre&gt;
&lt;p&gt;Au lieu de copier le contenu de &lt;code&gt;internalBuffer[file]&lt;/code&gt;,
&lt;code&gt;read&lt;/code&gt; prend &lt;code&gt;i&lt;/code&gt;, l'offset lui-même. Dans ce simple
exemple, le développeur n'a que peu de chances de se tromper de la sorte. Dans
un vrai système cela peut facilement se produire et on ne peut pas se permettre
de passer à côté.&lt;/p&gt;
&lt;p&gt;La racine du problème est la relation entre le contenu de
&lt;code&gt;testData&lt;/code&gt; et un autre facteur utilisé dans le code (l'offset
&lt;code&gt;i&lt;/code&gt; dans cet exemple). Une erreur du programme peut ainsi échapper
au test parce que le choix de &lt;code&gt;testData&lt;/code&gt; suit le même chemin.&lt;/p&gt;
&lt;h2&gt;Données aléatoires&lt;/h2&gt;
&lt;pre&gt;
testData = {random(), random(), random(), ... }
&lt;/pre&gt;
&lt;p&gt;Remplir &lt;code&gt;testData&lt;/code&gt; avec des données aléatoires est la première
bonne proposition. Les octets ne sont pas constants ou liés à quelque chose
comme l'offset, la longueur du fichier ou un identifiant. Cela prévient le
risque de confusion. Je n'ai aucun exemple de bug réaliste cette fois-ci.&lt;/p&gt;
&lt;p&gt;Les valeurs aléatoires soulèvent des questions et engendre parfois des
débats sans fin. Le test ne produira jamais deux fois le même
&lt;code&gt;testData&lt;/code&gt; d'une exécution à l'autre. Si un bug est découvert, il
pourrait ne plus être détecté lors de l'exécution suivante. Pour cette raison,
les données aléatoires ont leurs détracteurs. Il existent des solutions de
rechange, à discuter dans un autre post.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2009/12/24/Donn%C3%A9es-de-test-%3A-Attention-aux-pi%C3%A8ges-%21#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2009/12/24/Donn%C3%A9es-de-test-%3A-Attention-aux-pi%C3%A8ges-%21#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/465285</wfw:commentRss>
      </item>
    
  <item>
    <title>Développement piloté par les tests - 5 idées reçues</title>
    <link>http://blog.philippebernard.fr/post/2009/12/20/D%C3%A9veloppement-pilot%C3%A9-par-les-tests-Id%C3%A9es-re%C3%A7ues</link>
    <guid isPermaLink="false">urn:md5:f22640e85499f818db1170420e0249fa</guid>
    <pubDate>Sat, 19 Dec 2009 12:31:00 +0100</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
        <category>tdd</category><category>test</category>    
    <description>    &lt;p&gt;La méthode du &lt;a href=&quot;http://fr.wikipedia.org/wiki/Test_Driven_Development&quot;&gt;développement piloté par
les tests (Test Driven Development, TDD)&lt;/a&gt; dit d'écrire les tests unitaires
en même temps que le code. On répète le cycle suivant :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Écriture d'un test unitaire, alors que le code testé n'existe pas
encore.&lt;/li&gt;
&lt;li&gt;Exécution du test. Il doit échouer.&lt;/li&gt;
&lt;li&gt;Écriture du code.&lt;/li&gt;
&lt;li&gt;Exécution du test. Cette fois-ci il doit passer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;J'ai expérimenté le développement piloté par les tests il y a quelques
années avec l'outil emblématique de cette pratique, JUnit. Je suis depuis un
inconditionnel, que ça soit en Java ou en Ruby on Rails. J'ai naturellement
essayé de convertir mon entourage au TDD. L'évangéliste occasionnel que je suis
a été confronté à quelques préjugés. Parfois fausses ou plus souvent exagérées,
il convient de démonter les idées préconçues.&lt;/p&gt;
&lt;h2&gt;1. Ce n'est pas mon travail&lt;/h2&gt;
&lt;p&gt;Une réaction bien naturelle lorsqu'on travaille dans une équipe qui compte
des testeurs. Si un développeur écrit des tests, ne fait-il pas le travail d'un
autre ? N'est-il pas en train de se disperser ? Pas du tout.&lt;/p&gt;
&lt;p&gt;Il est entendu qu'un développeur commet des erreurs. On les retrouvera sous
la forme de bugs dans le code. Cependant, il y a aussi une qualité minimale
qu'on attend du développeur. D'abord, le code doit compiler. On imagine mal un
développeur qui livrerait à ses collègues un code contenant des erreurs de
syntaxe. Et puis, bien que ça ne soit pas la règle dans toutes les sociétés, le
code doit fonctionner. On ne parle pas d'un fonctionnement qui satisfasse
toutes les parties prenantes, ce sont les testeurs qui s'en assureront. Mais de
quelque chose &amp;quot;qui tourne&amp;quot;.&lt;/p&gt;
&lt;p&gt;C'est le premier objectif du TDD. Écrire un code qui marche. Plus
précisément, un code conforme aux intentions du développeur. Ne vous inquiétez
pas pour les testeurs, ils devront toujours vérifier que le logiciel est
conforme aux exigences, qu'il est robuste, performant...&lt;/p&gt;
&lt;h2&gt;2. Tester prend du temps&lt;/h2&gt;
&lt;p&gt;Le calcul est vite fait. Avec le TDD, on écrit le code et les tests. Sans,
on se contente du code. Alors, le TDD prend plus de temps ? Sans doute,
mais beaucoup moins qu'on pourrait le penser.&lt;/p&gt;
&lt;p&gt;En réalité, on se contente rarement d'écrire du code puisque, on l'a vu, on
veut s'assurer qu'il fonctionne. La méthode la plus primaire, mais tellement
naturelle, consiste à exécuter le code à la main. Le développeur lance le
programme qu'il écrit et interagit pour en vérifier le comportement. Dans le
cas d'une librairie, il ira même jusqu'à écrire un petit programme qui
l'utilise. Simple.&lt;/p&gt;
&lt;p&gt;Ces essais prennent du temps, surtout lorsque la portion de code à tester
est difficile à atteindre. Par exemple, si on essaie l'achat sur un site de
e-commerce, il faut à chaque fois ajouter des éléments au panier, entrer un nom
et une adresse postale, etc. Espérons qu'il n'y ait pas trop de bugs !&lt;/p&gt;
&lt;p&gt;Alors oui, le TDD prend du temps, mais il convient de faire ses comptes en
considérant tous les paramètres.&lt;/p&gt;
&lt;h2&gt;3. Tester ou faire des essais, ça revient au même&lt;/h2&gt;
&lt;p&gt;Écrire un test ou faire des essais, deux façons de parvenir au même
résultat : un programme qui se comporte correctement. Dans un premier
temps c'est vrai, mais à plus long terme il y a une grande différence.&lt;/p&gt;
&lt;p&gt;Les essais sont vites oubliés. Lorsqu'on écrit un programme pour tester une
librairie, on n'a généralement aucune velléité de réutilisation. Pas de
commentaires, un code sans structure réfléchie, des &amp;quot;print&amp;quot; ça et là pour que
le résultat soit visuel... Dès que le développement est fini, tout cela est
jeté.&lt;/p&gt;
&lt;p&gt;Les tests unitaires, eux, sont là pour rester. Les méthodes agiles s'en
servent de suites de non-régression, indispensables lors des épisodes de
refactoring. Quel que soit le cycle de développement, on trouve de nombreuses
utilités aux tests unitaires écrits des mois auparavant.&lt;/p&gt;
&lt;h2&gt;4. Tester est ennuyeux&lt;/h2&gt;
&lt;p&gt;Le test a parfois mauvaise presse. Rappelons d'abord qu'en TDD, on parle de
tests automatisés, et non de tests manuels. Cela est donc moins pénible et
intellectuellement plus satisfaisant.&lt;/p&gt;
&lt;p&gt;Une fois de plus, les tests sont à comparer aux essais auxquels on devra se
livrer en leur absence. Faire des essais peut être très simple, ce qui
constitue un avantage. En dehors de ce scénario qui se produit trop rarement,
faire des essais lasse rapidement.&lt;/p&gt;
&lt;p&gt;Les tests unitaires quant à eux sont de vrais programmes, destinés à être
conservés et écrits dans les règles de l'art. En ce sens, ils apportent la même
satisfaction que le code bien architecturé, indenté et commenté. Parfait pour
contenter les perfectionnistes que nous sommes souvent.&lt;/p&gt;
&lt;h2&gt;5. Tester ne paie qu'à moyen terme&lt;/h2&gt;
&lt;p&gt;Un de ces jours, les tests serviront de suite de non-régression. Mais là,
maintenant, tout de suite, il y a du code à écrire et les tests ne servent à
rien. Autant coder sans interruption et faire un seul essai final.&lt;/p&gt;
&lt;p&gt;Il me semble que les pratiques du développement n'évoluent pas dans ce sens.
Ces dernières années ont vu la fin des erreurs de compilation... pour certains
langages en tout cas. Autrefois, les éditeurs de code ne proposaient qu'une
coloration syntaxique rudimentaire et chaque compilation venait avec son lot de
surprises : une parenthèse manquante par ci, une faute de frappe par là.
On pouvait consacrer une partie de sa journée à corriger ces erreurs. Des IDE
comme Eclipse se sont depuis imposés et les éditeurs de quelques langages comme
Java sont évolués au point que chaque erreur de compilation est signalée sitôt
commise. Les corrections interviennent au fur et à mesure et la compilation est
désormais une formalité.&lt;/p&gt;
&lt;p&gt;Ce que les IDE ont fait pour la compilation, le TDD le fait pour le
fonctionnement. Bien sûr, on commet toujours les même bugs, mais ceux-ci sont
détectés et corrigés sur le champ. On a le sentiment d'écrire du code qui
marche du premier coup, ce qui est très appréciable. Inutile d'attendre pour
bénéficier des tests, ils paient immédiatement.&lt;/p&gt;
&lt;h2&gt;Et aussi...&lt;/h2&gt;
&lt;p&gt;L'énumération de ces idées reçues est l'occasion d'évoquer des avantages du
développement piloté par les tests : constitution d'une suite de test,
satisfaction du travail réalisé... Le TDD a également d'autres atouts, comme
celui de concevoir du code testable dès le départ. On se surprend souvent à
concevoir du code mieux structuré et moins monolithique justement parce que le
test correspondant semblait trop difficile à écrire de prime abord.&lt;/p&gt;
&lt;p&gt;Il existe de nombreuses ressources sur le Web à ce sujet et quelques
ouvrages. À vous de jouer, à vous de convaincre vos collègues !&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2009/12/20/D%C3%A9veloppement-pilot%C3%A9-par-les-tests-Id%C3%A9es-re%C3%A7ues#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2009/12/20/D%C3%A9veloppement-pilot%C3%A9-par-les-tests-Id%C3%A9es-re%C3%A7ues#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/469633</wfw:commentRss>
      </item>
    
  <item>
    <title>Qu'ai-je appris sur le test logiciel en tant qu'étudiant ?</title>
    <link>http://blog.philippebernard.fr/post/2009/12/05/Qu-ai-je-appris-sur-le-Test-Logiciel-en-tant-qu-%C3%A9tudiant</link>
    <guid isPermaLink="false">urn:md5:d68dae98edc3d374618ed7aadee21027</guid>
    <pubDate>Sat, 05 Dec 2009 11:18:00 +0100</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
        <category>formation</category><category>test</category>    
    <description>    &lt;p&gt;Cinq années d'études pour devenir Ingénieur. Comment ont-elles été mises à
profit ?&lt;/p&gt;
&lt;h2&gt;Développement&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/icons/passed.png&quot; alt=&quot;Passed&quot; style=&quot;float:left; margin: 0 1em 1em 0;&quot; title=&quot;Passed, Dec 2009&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Côté développement, aucun doute, le compte y est. Des cours de Pascal, C,
C++, Java, mais aussi des cours algorithmique, d'intelligence artificielle, de
conception d'interface graphique... Je ne vais pas plonger dans mes archives
pour faire le compte, mais il doit bien y avoir quelques centaines d'heures de
cours et de TD sur le sujet. A cela s'ajoutent les projets. Sans doute autant
de temps passé le soir et les weekend, seul ou en groupe, chez soi ou en &amp;quot;salle
Info&amp;quot; à coder et rédiger des rapports. Quant aux projets personnels, eux-aussi
contribuent à l'apprentissage. Qu'ils soient réalistes ou utopiques, tout juste
entamés ou achevés, ces réalisations apportent beaucoup aux passionnés. Enfin,
les stages sont l'occasion de pratiquer la programmation et forgent
l'expérience.&lt;/p&gt;
&lt;p&gt;De manière générale, les ingénieurs en informatique assidus sont des
développeurs tout à fait compétents à la fin de leurs études.&lt;/p&gt;
&lt;h2&gt;Gestion de projet&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/icons/passed.png&quot; alt=&quot;Passed&quot; style=&quot;float:left; margin: 0 1em 1em 0;&quot; title=&quot;Passed, Dec 2009&quot; /&gt;&lt;/p&gt;
&lt;p&gt;La gestion de projet est un autre sujet important. Notre travail s'inscrit
toujours dans le cadre d'un projet, quel que soit sa forme. Il est donc
important d'en maitriser les rudiments. De plus, la gestion de projet est l'une
des évolutions naturelles de l'ingénieur (l'autre étant l'expertise technique).
Nos études devraient logiquement nous y préparer.&lt;/p&gt;
&lt;p&gt;J'ai reçu quelques cours de gestion de projet, parfois teintés de Merise. On
m'a évidemment présenté le cycle en V, et les méthodes itératives. Quant aux
méthodes agiles, elles étaient sans doute un peu trop récentes. Quelques
travaux pratiques étaient au programme, avec rédaction de cahier des charges et
autres. Tout cela a du représenter une centaine d'heures. Par contre, pas de
planification, d'estimation de charge ou de diagramme de Gantt.&lt;/p&gt;
&lt;p&gt;Et pour ce qui est des à côtés, le constat est là-aussi bien différent. Si
beaucoup d'entre nous ont volontiers appris de nouveaux langages et
environnements simplement par passion, moins se sont lancés dans la gestion de
projet pure juste par goût.&lt;/p&gt;
&lt;p&gt;Faut-il conclure que la gestion de projet ne m'a pas été suffisamment
enseignée ? Je ne pense pas. On ne commence jamais sa carrière en tant que
chef de projet ou assimilé. Études ou pas, il est nécessaire d'acquérir de
l'expérience sur le terrain. Par conséquent, on peut aborder le monde du
travail avec une connaissance partielle. Je ne me suis pas retrouvé démuni en
commençant à travailler, c'est l'essentiel.&lt;/p&gt;
&lt;h2&gt;Test&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/icons/failed.png&quot; alt=&quot;Failed&quot; style=&quot;float:left; margin: 0 1em 1em 0;&quot; title=&quot;Failed, Dec 2009&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Cette fois-ci, le constat est très différent. Le test ? Comme il
constitue la partie droite du &amp;quot;V&amp;quot;, il a bien fallu m'en parler. J'ai aussi
suivi un cours sur le sujet, une bonne partie étant consacrée au domaine
spécifique de la modélisation. &amp;quot;Plan de test&amp;quot;, &amp;quot;test unitaire&amp;quot;, &amp;quot;test
automatisé&amp;quot;, autant de termes dont on ne m'a pas parlé (ou alors pas assez, car
je ne m'en souviens pas).&lt;/p&gt;
&lt;p&gt;Lors d'un stage, j'avais réalisé un site web qui impliquait des transactions
bancaires. C'était un projet compliqué que j'avais accompli sans aide et dont
j'étais assez fier. Plus tard, lors d'un entretien pour un autre stage, mon
interlocuteur m'a demandé comment ce site avait été testé. J'ai répondu d'un
laconique &amp;quot;avec du bon sens&amp;quot;, façon d'indiquer que rien n'avait été fait. En
cet instant, non seulement je réalisais que mon précédent projet n'avait pas
été testé, mais en plus j'ignorais complètement ce qu'il aurait fallu faire
pour cela. A Bac+4, je savais déjà programmer mais je n'avais aucune idée de la
façon de valider le fruit de mon travail.&lt;/p&gt;
&lt;p&gt;Puis j'ai entamé mon stage de dernière année, dont le sujet était... le
test. Je ne savais pas en quoi ça consistait. Des personnes autour de moi
savaient bien de quoi il s'agissait, mais il n'y avait pas de testeur à part
entière dans mon équipe. Il a fallu apprendre.&lt;/p&gt;
&lt;h2&gt;Qu'en penser ?&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/icons/question_mark.png&quot; alt=&quot;Question&quot; style=&quot;float:left; margin: 0 1em 1em 0;&quot; title=&quot;Question, Dec 2009&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Mon cursus n'a rien d'atypique. La plupart de mes confrères ont également
suivi des études d'informatique plus ou moins généralistes, et le test n'est
qu'une matière secondaire.&lt;/p&gt;
&lt;p&gt;De prime abord, on peut évidemment déplorer la place marginale que le test
occupe souvent. Même si les entreprises ont avant tout besoin développeurs,
elles doivent également valider leurs logiciels. Le professionnalisme est
souhaitable dans un domaine comme dans l'autre.&lt;/p&gt;
&lt;p&gt;Cependant, je vois un signe positif dans cet apparent délaissement. Selon
moi, pour bien tester, il faut d'abord savoir programmer. A l'exception des
tests métier, tester nécessite une bonne compréhension de l'informatique en
général. On pourrait ainsi considérer que les études classiques ne constituent
qu'une introduction à la formation de testeur. Certes cette vision idyllique ne
saurait conclure valablement le débat, mais pourquoi ne pas finir ce post sur
une note positive ?&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2009/12/05/Qu-ai-je-appris-sur-le-Test-Logiciel-en-tant-qu-%C3%A9tudiant#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2009/12/05/Qu-ai-je-appris-sur-le-Test-Logiciel-en-tant-qu-%C3%A9tudiant#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/464924</wfw:commentRss>
      </item>
    
  <item>
    <title>Le test qui ne pouvait échouer</title>
    <link>http://blog.philippebernard.fr/post/2009/12/03/Le-test-qui-ne-pouvait-%C3%A9chouer</link>
    <guid isPermaLink="false">urn:md5:f733acddf78b4c0de8783df1bcc2a8f9</guid>
    <pubDate>Thu, 03 Dec 2009 19:50:00 +0100</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
        <category>technique de test</category><category>test</category>    
    <description>    &lt;p&gt;Bien souvent, on s'attend à ce que les tests passent. Notre outil nous
présente un rassurant &amp;quot;Tous les tests sont passés avec succès&amp;quot; ou quelque chose
du genre. Idéal une veille de livraison.&lt;/p&gt;
&lt;p&gt;Quid d'un test qui nous ferait toujours ce plaisir ?&lt;/p&gt;
&lt;p&gt;Testons une méthode de vérification de PIN. &lt;code&gt;verifyPIN&lt;/code&gt; retourne
&lt;code&gt;true&lt;/code&gt; lorsque le PIN de 4 chiffres passé en paramètre est correct,
&lt;code&gt;false&lt;/code&gt; sinon. Un test négatif est recommandé, qu'en
dites-vous ? Dans cette version simplifiée, on prend la bonne valeur du
PIN. On en modifie l'un des chiffres, puis on soumet cette valeur altérée à
&lt;code&gt;verifyPIN&lt;/code&gt; en s'attendant à ce qu'elle retourne &lt;code&gt;false&lt;/code&gt;.
On teste chaque position du PIN (le premier chiffre, le second, etc.) afin de
s'assurer que chacune est impliquée dans la vérification :&lt;/p&gt;
&lt;pre&gt;
// Testons toutes les positions d'un PIN à 4 chiffres
for (int i = 0; i &amp;lt; 4; i++) {
  // On récupère le vrai PIN
  pin = getPIN();
  // On le modifie
  pin[i] = (pin[i] + 1) % 10; // 0 -&amp;gt; 1, 1 -&amp;gt; 2, ..., 9 -&amp;gt; 0
  // A partir de maintenant, pin n'est plus correct

  // L'authentication devrait échouer
  assertFalse(verifyPIN(pin));
}
&lt;/pre&gt;
&lt;p&gt;Le test passe. Bonne nouvelle pour la livraison de demain. En fait, ce n'est
pas une bonne nouvelle, par la combinaison de deux hasards :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pour une raison ou pour une autre, &lt;code&gt;getPIN&lt;/code&gt; ne retourne pas la
bonne valeur du PIN. Un problème dans la configuration du test
peut-être ?&lt;/li&gt;
&lt;li&gt;Il se trouve que &lt;code&gt;verifyPIN&lt;/code&gt; est buggué. &lt;code&gt;verifyPIN&lt;/code&gt;
ne vérifie pas le dernier chiffre du PIN (une faute de frappe dans la longueur
de la comparaison ?). Par conséquent, si le PIN est &amp;quot;1234&amp;quot;,
&lt;code&gt;verifyPIN&lt;/code&gt; accepte naturellement &amp;quot;1234&amp;quot;, mais aussi &amp;quot;1235&amp;quot; et
&amp;quot;1239&amp;quot;. Ouch.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce bug est critique et pourtant il n'est pas détecté par notre test qui est
pourtant conçu pour cela. Que s'est-il passé ? Le but du test est de
soumettre un PIN avec un seul chiffre incorrect. Comme &lt;code&gt;getPIN&lt;/code&gt; ne
retourne pas la bonne valeur, il y a toujours des erreurs sur les trois
premiers chiffres que &lt;code&gt;verifyPIN&lt;/code&gt; détecte, peu importe que
quatrième. Ainsi que le test l'attend, l'authentification échoue, mais pas pour
la bonne raison.&lt;/p&gt;
&lt;p&gt;Le bug ne sera pas détecté et le produit sera livré demain comme prévu. Un
jour, quelqu'un se rendra compte de l'erreur et là...&lt;/p&gt;
&lt;h2&gt;Donnons-lui une chance d'échouer&lt;/h2&gt;
&lt;p&gt;Il existe plusieurs moyens de rendre un test résistant. Pour un test négatif
de ce genre, une méthode classique est d'ajouter un cas positif :&lt;/p&gt;
&lt;pre&gt;
pin = getPIN();
// Avec le bon PIN, l'authentification doit réussir
assertTrue(verifyPIN(pin));

// Testons toutes les positions d'un PIN à 4 chiffres
for (int i = 0; i &amp;lt; 4; i++) {
  ... // Pas d'autre changement
}
&lt;/pre&gt;
&lt;p&gt;Le test est plus sûr. Désormais, lorsque &lt;code&gt;getPIN&lt;/code&gt; retourne une
mauvaise valeur, le test échoue immédiatement puisque &lt;code&gt;verifyPIN&lt;/code&gt;
indique d'emblée que le PIN est incorrect. Certes, le test sortira failed pour
une mauvaise raison (une bonne raison étant un bug de code), mais au moins
l'erreur ne passera pas inaperçue et le testeur fera le nécessaire pour la
corriger. Au pire, on livrera après-demain.&lt;/p&gt;
&lt;h2&gt;Comment ça &amp;quot;paranoïaque&amp;quot; ?&lt;/h2&gt;
&lt;p&gt;La vérification du PIN en début de test réduit considérablement le risque
évoqué ci-dessus. Toute personne raisonnable s'arrêterait là.&lt;/p&gt;
&lt;p&gt;Cependant, &amp;quot;raisonnable&amp;quot; est tout juste un minimum pour nous testeurs. D'un
côté, nous traquons les bugs, sortons des sentiers battus pour trouver les
scénarios litigieux, cherchons les failles... De l'autre, nous écrivons des
tests et prenons le risque de commettre exactement les même erreurs que celles
que nous recherchons. Et dans notre cas, personne n'est là pour tester notre
travail. Nous devons nous efforcer de trouver nos propres erreurs. Pas
simple.&lt;/p&gt;
&lt;p&gt;Pour reprendre l'exemple du PIN, on peut rendre le test encore plus
sûr :&lt;/p&gt;
&lt;pre&gt;
// Testons toutes les positions d'un PIN à 4 chiffres
for (int i = 0; i &amp;lt; 4; i++) {
  // On récupère le vrai PIN
  pin = getPIN();

  // Avec le bon PIN, l'authentification doit réussir
  assertTrue(verifyPIN(pin));

  // On le modifie
  pin[i] = (pin[i] + 1) % 10; // 0 -&amp;gt; 1, 1 -&amp;gt; 2, ..., 9 -&amp;gt; 0
  // A partir de maintenant, pin n'est plus correct

  // L'authentication devrait échouer
  assertFalse(verifyPIN(pin));
}
&lt;/pre&gt;
&lt;p&gt;La valeur de &lt;code&gt;getPIN&lt;/code&gt; est maintenant vérifiée à chaque itération.
En quoi est-ce plus sûr ? A moins d'une erreur de ma part dans le code qui
précède, cela n'apporte rien. Mais nous ne cherchons pas à éviter les erreurs
que nous connaissons : lorsqu'on a conscience d'une erreur, on la corrige,
tout simplement. Il s'agit plutôt d'anticiper des problèmes typiques. Comme
dans cet exemple :&lt;/p&gt;
&lt;pre&gt;
// On récupère le vrai PIN
pin = getPIN();

// Testons toutes les positions d'un PIN à 4 chiffres
for (int i = 0; i &amp;lt; 4; i++) {
  // Avec le bon PIN, l'authentification doit réussir
  assertTrue(verifyPIN(pin));

  // On le modifie
  pin[i] = (pin[i] + 1) % 10; // 0 -&amp;gt; 1, 1 -&amp;gt; 2, ..., 9 -&amp;gt; 0
  // A partir de maintenant, pin n'est plus correct

  // L'authentication devrait échouer
  assertFalse(verifyPIN(pin));
}
&lt;/pre&gt;
&lt;p&gt;L'appel à &lt;code&gt;getPIN&lt;/code&gt; est maintenant sorti de la boucle
&lt;code&gt;for&lt;/code&gt;. Après tout, il n'est pas utile de l'appeler quatre fois
n'est-ce pas ? En réalité, oui, c'est indispensable.&lt;/p&gt;
&lt;p&gt;Le test veut soumettre à &lt;code&gt;verifyPIN&lt;/code&gt; un PIN dont tous les
chiffres sont corrects sauf un. Or, en l'état, ce n'est pas ce que fait le
test. En effet, puisque &lt;code&gt;pin&lt;/code&gt; n'est plus réinitialisé en début de
boucle &lt;code&gt;for&lt;/code&gt;, les irrégularités introduites dans &lt;code&gt;pin&lt;/code&gt;
s'accumulent d'une itération à l'autre. A la quatrième itération, ce n'est pas
seulement le dernier mais tous les chiffres de pin qui sont incorrects. Une
fois de plus, le bug ne serait pas découvert... si la vérification de
&lt;code&gt;pin&lt;/code&gt; n'était pas faite en début de boucle. Grâce à elle, lors de la
seconde itération, le test échouera en constatant que
&lt;code&gt;verifyPIN(pin)&lt;/code&gt; retourne &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Les self-tests ne sont pas toujours facile à introduire. On pourrait
également s'interroger sur les éventuels effets de bord introduits par les
appels supplémentaires à &lt;code&gt;verifyPIN&lt;/code&gt;. C'est néanmoins une technique
à garder à l'esprit, spécialement dans le cadre de tests négatifs.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2009/12/03/Le-test-qui-ne-pouvait-%C3%A9chouer#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2009/12/03/Le-test-qui-ne-pouvait-%C3%A9chouer#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/464275</wfw:commentRss>
      </item>
    
  <item>
    <title>Comment passer l'examen CFTL/ISTQB niveau Fondation ?</title>
    <link>http://blog.philippebernard.fr/post/2009/11/29/Comment-passer-l-examen-CFTL-ISTQB-niveau-Fondation</link>
    <guid isPermaLink="false">urn:md5:60a512d7f03aa4071367f9fefd7e87ee</guid>
    <pubDate>Sun, 29 Nov 2009 15:19:00 +0100</pubDate>
    <dc:creator>Philippe Bernard</dc:creator>
        <category>cftl</category><category>formation</category><category>istqb</category><category>test</category>    
    <description>    &lt;p&gt;&lt;img src=&quot;http://blog.philippebernard.fr/public/istqb.jpg&quot; alt=&quot;ISTQB Certified Tester&quot; style=&quot;float:left; margin: 0 1em 1em 0;&quot; title=&quot;ISTQB Certified Tester, Nov 2009&quot; /&gt;Le &lt;a href=&quot;http://www.cftl.net/&quot;&gt;CFTL&lt;/a&gt;
permet de passer l'examen pour obtenir la certification ISTQB, niveau
Fondation. Cette certification est de plus en plus populaire en France et dans
le monde. De quoi s'agit-il et comment s'y prendre ?&lt;/p&gt;
&lt;h2&gt;L'examen&lt;/h2&gt;
&lt;p&gt;L'examen porte sur le &lt;a href=&quot;http://www.istqb.org/downloads/syllabi/SyllabusFoundation.pdf&quot;&gt;Foundation
Level Syllabus&lt;/a&gt;, soit le &lt;a href=&quot;http://www.cftl.net/cms/files/Dokumente/frSyllabusFoundation_v2005.pdf&quot;&gt;Syllabus
Niveau Fondation&lt;/a&gt;, traduit en français par le CFTL (avec une version de
retard à ce que je comprends, bien que cela ne fasse pas grande différence). Ce
document couvre l'essentiel du test logiciel : intérêt du test, place du
test dans le cycle de vie, techniques de test, etc.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.cftl.net/index.php?id=12,0&amp;amp;sitelang=fr&quot;&gt;L'inscription&lt;/a&gt; se
fait en ligne sur le site du CFTL.&lt;/p&gt;
&lt;p&gt;L'épreuve est un QCM de 40 questions. Chaque question s'accompagne de 4
réponses dont une seule est correcte. Il n'y a pas de pénalité : une
mauvaise réponse ne retire pas de point. Pour passer l'examen, il faut au
minimum 65% de réponses correctes, soit 26 bonnes réponses.&lt;/p&gt;
&lt;p&gt;L'examen dure une heure. C'est une durée tout à fait suffisante. Les
questions sont relativement simples : soit on sait, soit on ne sait pas.
Quelques difficultés de formulation ou de petits exercices peuvent demander un
peu de temps, mais globalement toutes les questions trouveront réponse
rapidement. Ainsi on remplit le questionnaire en 45 minutes environ, tandis que
les 15 minutes restantes sont bien utiles pour se relire et revenir sur les
questions délicates.&lt;/p&gt;
&lt;p&gt;Pendant l'épreuve, les documents sont interdits, de même que les brouillons.
Si vous devez noter quelque chose, vous pouvez griffonner sur le questionnaire
lui-même. Vos commentaires seront de toute façon ignorés, seules les croix
comptent.&lt;/p&gt;
&lt;p&gt;Les résultats sont communiqués par mail sous une semaine. Par la suite, le
candidat reçoit un justificatif par courrier.&lt;/p&gt;
&lt;h2&gt;Préparer l'examen&lt;/h2&gt;
&lt;p&gt;Il existe plusieurs options pour se préparer à l'examen. A vous de trouver
celle qui vous convient.&lt;/p&gt;
&lt;h3&gt;Aucune préparation !&lt;/h3&gt;
&lt;p&gt;Se présenter à l'examen les mains dans les poches, après tout pourquoi
pas ? Le niveau Fondation couvre les bases du test logiciel. Lorsqu'on a
plusieurs d'années d'expérience, on peut estimer posséder le bagage
nécessaire.&lt;/p&gt;
&lt;p&gt;Bien que cette approche soit raisonnable, je la déconseille. Même si vous
avez la connaissance pour vous lancer, je vous recommande d'éviter deux
difficultés :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vocabulaire&lt;/strong&gt; : Ça n'a l'air de rien, mais il est
facile de se laisser surprendre par un point de vocabulaire. L'ISTQB définit un
glossaire dont on retrouve les termes dans le questionnaire. Il est donc utile
de consulter le &lt;a href=&quot;http://www.gasq.org/boards/cftl/cms/files/Dokumente/Glossaire%20des%20tests%20de%20logiciel%20-%202%200%20F%20ISTQB.pdf&quot;&gt;
glossaire français&lt;/a&gt; afin d'éviter les surprises.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Questionnaire&lt;/strong&gt; : La forme d'un QCM peut laisser penser
que l'examen est plus facile que si les réponses avaient été libres. C'est en
partie vrai, et cependant les différents choix peuvent laisser perplexes. On a
parfois l'impression que toutes les réponses sont bonnes, alors qu'une seule
est correcte. En réalité la formulation de la question permet toujours d'isoler
la bonne réponse, encore faut-il acquérir certains réflexes. Le plus simple est
de se familiariser en effectuant un examen blanc. &lt;a href=&quot;http://knowledge-department.fr/certifiedtesterfr/examens/nouveau-examen-a-blanc.html&quot;&gt;
Knowledge Department en propose un d'une vingtaine de questions&lt;/a&gt;. On trouve
aussi des examens en anglais.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Au delà de la préparation, l'examen blanc vous permettra de déterminer si
vous pouvez vraiment vous présenter à l'examen sans apprentissage ou si
quelques révisions s'imposent.&lt;/p&gt;
&lt;p&gt;Coût de cette approche : 250€, soit le prix de l'examen.&lt;/p&gt;
&lt;h3&gt;Effectuer une formation puis passer l'examen&lt;/h3&gt;
&lt;p&gt;Des sociétés accréditées proposent des formations de 3 jours. Ces formations
se focalisent sur le syllabus du CFTL, de sorte qu'elles préparent
véritablement au passage de l'examen. C'est en fait le package &amp;quot;formation +
examen&amp;quot; qui est proposé : les auditeurs passent l'examen aussitôt la
formation terminée. Tant mieux, autant battre le fer tant qu'il est chaud. Par
contre, j'ignore si c'est systématiquement ainsi que cela se passe. Vous
devriez donc vous renseigner.&lt;/p&gt;
&lt;p&gt;Le site du CFTL recense les &lt;a href=&quot;http://www.cftl.net/index.php?id=23,0&amp;amp;sitelang=fr&quot;&gt;sociétés qui dispensent
ces formations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;N'ayant pas assisté à une telle formation, je ne peux pas les commenter
d'avantage. Si vous-même vous avez cette expérience, je vous invite à laisser
un commentaire pour donner vos impressions.&lt;/p&gt;
&lt;p&gt;Coût de cette approche : environ 1500€, selon la formation.&lt;/p&gt;
&lt;h3&gt;Auto-formation&lt;/h3&gt;
&lt;p&gt;Moins cher qu'une formation et plus prudent que la simple confiance en soi,
il est possible de se préparer soi-même à l'examen.&lt;/p&gt;
&lt;p&gt;On peut opter pour le &lt;a href=&quot;http://www.cftl.net/cms/files/Dokumente/frSyllabusFoundation_v2005.pdf&quot;&gt;syllabus
publié par le CFTL&lt;/a&gt;. Après tout c'est sur ce document que porte l'examen,
impossible de se tromper. Malheureusement ce document est un peu austère. Le
professionnel pressé saura y trouver les informations dont il a besoin pour se
présenter à l'examen en toute quiétude. Le débutant risque en revanche d'avoir
plus de mal à aborder ce document. Jetez-y un coup d'œil et voyez si c'est la
formule qui vous convient ou pas.&lt;/p&gt;
&lt;p&gt;Autre possibilité, il existe plusieurs ouvrages en anglais qui traitent du
syllabus ISTQB niveau Fondation. J'ai opté pour &lt;a href=&quot;http://www.amazon.com/Foundations-Software-Testing-ISTQB-Certification/dp/1844809897&quot;&gt;
Foundations of Software Testing: ISTQB Certification&lt;/a&gt; (vous trouverez sur
Amazon.com commentaires et critiques des lecteurs, mais pour commander passez
par &lt;a href=&quot;http://www.amazon.fr/Foundations-Software-Testing-ISTQB-Certification/dp/1844809897&quot;&gt;
Amazon.fr&lt;/a&gt;... ou par un autre site). Ce livre est très bien :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Véritable préparation à l'examen&lt;/strong&gt; : Comme promis sur
la couverture, le livre suit le syllabus afin que le lecteur se familiarise
avec ce qu'il va rencontrer lors de l'examen. Chaque chapitre s'achève par un
QCM de quelques questions, et le dernier chapitre, qui traite de l'examen
lui-même, comporte un QCM complet de 40 questions. Ainsi, en répondant à toutes
les questions, on effectue l'équivalent de deux examens blancs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pas trop de blabla&lt;/strong&gt; : C'est toujours un plaisir de
lire, mais autant aller à l'essentiel. Le livre compte 200 pages de contenu,
auxquelles s'ajoutent le glossaire, les réponses aux QCM, etc. C'est le bon
volume.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agréable à lire&lt;/strong&gt; : Cet ouvrage se veut comme un livre
à lire, et non une énumération rébarbative. En fait, il constitue une bonne
introduction au test logiciel, ISTQB ou pas. On pourra donc s'y plonger sans
que ça soit une corvée.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il y a évidemment un risque à se former en anglais tandis que l'examen est
en français. Il serait malheureux de se laisser attraper par une traduction
improbable. Le &lt;a href=&quot;http://www.gasq.org/boards/cftl/cms/files/Dokumente/Glossaire%20des%20tests%20de%20logiciel%20-%202%200%20F%20ISTQB.pdf&quot;&gt;
glossaire du CFTL&lt;/a&gt; est bilingue, ce qui permet de repérer les traductions
délicates. A vrai dire, le parcours en diagonale auquel je me suis livré n'a
pas révélé de piège : &amp;quot;regression testing&amp;quot; devient bien &amp;quot;test de
régression&amp;quot;, etc. Pas de piège. Cela s'est vérifié lors de l'examen.&lt;/p&gt;
&lt;p&gt;Quid d'un ouvrage français pour se préparer ? Il existe bien un livre
prometteur, &lt;a href=&quot;http://www.amazon.fr/Pratique-tests-logiciels-Pr%C3%A9paration-certification/dp/2100518623&quot;&gt;
Pratique des tests logiciels : Concevoir et mettre en oeuvre une stratégie
de tests - Préparation à la certification ISTQB&lt;/a&gt;. Malheureusement, il est
difficile de déterminer ce qu'il apporte vraiment par rapport à la
certification ISTQB. On parle simplement de &amp;quot;préparer au passage de la
certification ISTQB du métier de testeur&amp;quot;. L'ouvrage se focalise-t-il sur cet
objectif ? Ou s'agit-il simplement d'une caractéristique dont peut se
prévaloir tout texte traitant du test logiciel ? Le niveau visé n'est même
pas cité : Fondation ? Avancé ? En l'absence de détails, j'ai
préféré m'abstenir. Si vous avez lu ce livre, publiez un commentaire, ici ou
ailleurs, afin d'éclairer les lecteurs hésitants !&lt;/p&gt;
&lt;p&gt;Coût de cette approche :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un livre : 30€ environ&lt;/li&gt;
&lt;li&gt;L'examen : 250€&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Bonne certification !&lt;/h2&gt;
&lt;p&gt;Un débutant trouvera avantage à passer l'examen CFTL/ISTQB niveau Fondation.
Il couvre l'essentiel du test logiciel. Pour le testeur expérimenté, l'examen
correspond plus à une validation d'acquis qu'à un véritable apprentissage.
C'est un bon point de départ pour faire reconnaitre son expérience.&lt;/p&gt;
&lt;p&gt;Quel que soit votre niveau et la façon dont vous préparerez l'examen, je
vous souhaite bonne chance !&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.philippebernard.fr/post/2009/11/29/Comment-passer-l-examen-CFTL-ISTQB-niveau-Fondation#comment-form</comments>
      <wfw:comment>http://blog.philippebernard.fr/post/2009/11/29/Comment-passer-l-examen-CFTL-ISTQB-niveau-Fondation#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.philippebernard.fr/feed/atom/comments/432731</wfw:commentRss>
      </item>
    
</channel>
</rss>