Delphi

Un article de Agora2ia.


Sommaire

Présentation

Site officiel.


En 1995, après neuf versions de compilateurs Turbo et Borland Pascal, qui ont progressivement étendu le langage, Borland a sorti Delphi, faisant de Pascal un langage de programmation visuel.

Delphi étend le langage Pascal dans plusieurs directions, incluant plusieurs extensions orienté objet différentes des autres variétés de Pascal Objet, les incluant dans le compilateur Borland Pascal avec Objets.

Extrait de L'histoire du Pascal


Delphi est un langage compilé.


Caractéristiques techniques

D'après la présentation du c2.com de Delphi.

  • Pas de garbage collector.
  • Objet par référence par défaut (donc déférencé).
  • Héritage simple.
  • Référence explicite aux méthodes parent hérités.
  • Méthodes de classe.
  • Une classe commune à tout objet : TObject.
  • Notion de property : l'attribut membre peut alors être utilisé via des getter/setter.
  • Notion d'interface (classe abstraite sans attribut ni implémentation).
  • Surcharge de fonction.
  • Construction polymorphique d'instanc ???
  • Un objet peut être casté en un type qu'il n'implémente pas.


Caractéristiques intéressantes

  • Fichiers sources.
  • Notion de classe et module !
  • Le nom de la structure impose celui du fichier dans lequel elle est définie ???
  • Exceptions.
  • Remaniements.
  • Evénements et envoi de messages.
  • IHM.

Débuter

Composants


Delphi et l'Extreme Programming

La présentation du c2.com de Delphi, orientée technique, donne une impression sur les aptitudes à l'Agilité du langage...

Increased Productivity with Refactoring, Unit Testing, Help Insight, Error Insight, and Sync Edit in Borland Delphi s'attarde sur les nouvelles fonctionnalités de l'IDE Borland : certaines amènent de réelles améliorations.

A titre d'illustration de ce qui se fait à côté, je prendrais des exemples de ma plus récente expérience, à savoir Java et l'IDE IntelliJ IDEA 5.1.

Peut-être serait il judicieux d'étendre cette comparaison à d'autres critères et d'autres langages...


Gestionnaires de version

En tant que LangageCompilé, le code source Delphi se trouve dans des fichiers texte : on peut donc utiliser son GestionnaireDeVersion favori tel que CVS ou Subversion.

Ces GestionnaireDeVersion ne sont pas intégrés dans l'IDE Delphi, on utilise généralement Tortoise qui permet de faire les commit au niveau du gestionnaire de fichier de Windows.

Le gestionnaire de version le mieux intégré a Delphi est FreeVCS devenu depuis 2 ans JediVCS. Ce gestionnaire s'intègre totalement dans l'IDE de Delphi version 5 a 2006

Pour rappel, il est fortement recommandé en ExtremeProgramming de remonter plusieurs fois par jour dans le référentiel du GestionnaireDeVersion ("faire un commit"), et idéalement de l'ordre d'une fois par heure. D'où l'importance que l'IDE intègre pleinement le GestionnaireDeVersion.

Le remaniement

En tant que langage OrientéObjet, Delphi doit supporter la majorité des Remaniements identifiés par MartinFowler dans Refactoring: Improving the Design of Existing Code.


Le nombre de Remaniements offert par l'IDE peut favoriser cette pratique :


Il faut cependant garder à l'esprit que le nombre de Remaniements proposés par l'IDE n'est pas tout : leur qualité compte tout autant si ce n'est plus. Prenons l'exemple de l' Extract method. L'IDE est-il capable de détecter des portions de code similaires (le corps de la future méthode) lorsque le nom de variables diffèrent ?... Etc...

Idéalement, toute modification de code qui n'est pas un ajout fonctionnel devrait être un Remaniement. Changer le nom d'un variable n'est pas un "Search and replace" mais bien un "Rename variable".

En effet, en raison de la PropriétéCollectiveDuCode, les Remaniements doivent être fréquent lorsque l'on travaille en TestDrivenDevelopment, voire en ExtremeProgramming. D'où l'importance que l'IDE intègre pleinement les Remaniements les plus fréquents .


Les tests unitaires

L'IDE Broland Delphi 2005 permet la création projet de tests, sorte de mirroir du projet applicatif.


DUnit


Bubelen

Bubelen is a system for building and maintaining bubbles. A bubble is a piece of code for testing, developing, profiling, debugging, and stress testing. Bubbles are similar to boxes which are used in box testing (sometimes also referred to as unit testing), however bubbles are not designed with the only goal being testing. More information on the bubble philosophy is included in the article, Bubbles - Producing efficient and reliable code, first time, every time.


Delphi Unit Test Expert

Delphi Unit Test Expert : The goal of the Delphi Unit Test Expert project is to build a tool for easy create test application for Delphi Units. Features of Delphi Unit Test Expert:

  • AddIn Delphi Expert
  • Test procedure infrastructure
  • Special functions for test procedure


AQtest

http://www.automatedqa.com/

AQtest automates and manages functional tests, unit tests and regression tests, for applications written with VC++, VB, Delphi, C++Builder, Java or VS.NET. It also supports white-box testing, down to private properties or methods. External tests can be recorded or written in three scripting languages (VBScript, JScript, DelphiScript). Using AQtest as an OLE server, unit-test drivers can also run it directly from application code. AQtest automatically integrates AQtime when it is on the machine. Entirely COM-based, AQtest is easily extended through plug-ins using the complete IDL libraries supplied. Plug-ins currently support Win32 API calls, direct ADO access, direct BDE access, etc.


Test First Design et Test Driven Development

Sommairement, le TestFirstDesign est le fait d'écrire tous les tests unitaires avant la moindre ligne de code applicatif, ce qui implique une conception préalable, même sommaire. Le TestDrivenDevelopment (TDD) quand à lui implique une alternance permanente et fréquente entre l'écriture d'un test unitaire et l'écriture du code applicatif associé. Cela induit que la conception de l'application émerge à mesure que l'on écrit les tests, et peut changer à tout moment sous l'impulsion des tests. Le TDD peut donc être vu comme le stade supérieur du TestFirstDesign, pour ne pas dire ultime. Mais comme ces deux techniques requièrent les mêmes fonctionnalités de la part de l'IDE, nous ne parlerons dans la suite de cet article que du TestFirstDesign, en considérant comme acquis que cela s'applique indifféremment au TestDrivenDevelopment dans notre cas.

La facilité de mise en oeuvre de ces techniques est encore liée à l'IDE.

Ansi, par défaut le Studio Delphi 2005 permet, via un wizard, de sélectionner une classe parmis celle que l'on a codé, puis les méthodes de cette classe que l'on souhaite tester. Un squelette de classe de test unitaire est alors généré. Nous sommes ici dans le cadre "normal" de développement, c'est à dire à l'opposé du TestFirstDesign puisque le test unitaire est écrit après le code/classe à tester.

Une première parade est d'utiliser les Live Template de Studio 2005. En renseignant un nom de classe (pas encore codée), le live template génère d'abord la classe de test unitaire TestMyClass (comme héritant d'un test-case de DUnit) et éventuellement les méthodes de setUp / tearDown et une première méthode de test vide testMyMethod.

La prochaine étape serait que, une fois écrit (dans la classe de test) un appel de méthode sur une instance de la classe applicative testée, une "intention" (selon la sémantique IntelliJ) dans la fenêtre de code de la classe de test suggère de créer la méthode en question dans la classe applicative. Si le développeur accepte l'IDE créerait effectivement la méthode, en demandant confirmation sur les informations ambiguës (nom/type de(s) paramètres, type de retour...). L'IDE pointerait ensuite sur la méthode fraîchement créée dans la classe applicative.

Enfin, un raccourci clavier permettrait à tout instant de basculer entre le code de la classe testée et le code de la classe de test unitaire.


Tests fonctionnels

Les tests fonctionnels, ou d'acceptance, ou de recette, visent à valider les fonctionnalités l'application, son utilisation. Il est important qu'ils soient automatisés, si l'on veut pouvoir les jouer fréquemment. L'idée sous jacente étant toujours de détecter au plus vite le moindre bug ou la moindre régression.


Un exemple de test release serait :

  1. Construire la base de données utilisée pour le test release (de développement ou d'intégration) à l'image de celle de la production.
  2. Remplir cette base avec un jeu restreint mais pertinent de données pour la fonctionnalité testée (véritable difficulté).
  3. Lancer l'application sur cette base.
  4. Saisir le login et le mot de passe d'un utilisateur dans la fenêtre de login, et cliquer sur "valider".
  5. Cliquer sur l'entrée de menu "Saisir un nouvelle fiche client".
  6. Saisir le nom "Bobo".
  7. Cliquer sur "Valider".
  8. S'assurer alors que l'on a bien l'apparition d'une fenêtre dont le titre est "Erreur", et le texte contenu indique "L'adresse est obligatoire pour valider".


De façon générale, la solution déployée dépend de la technologie utilisée.

En Java:

  • Pour une application Web on pourra utiliser Canoo WebTest.
  • Pour une application "client riche" en Swing, on pourra utiliser JfcUnit ou UIspec4J.

Ces solutions imposent un peu de discipline dans le nommage de ses composants/classes graphiques.


Pour ma part, j'utilise la solution suivante. On décrit le scénario de test dans un fichier XML sous forme d'actions de haut niveau : click, assertFrame, etc. Puis un moteur basé sur le principe des tâches Ant transforme ce scénario Xml en test-case JFCUnit. Ce dernier récupère les objets de nos IHM Swing d'après les noms indiqués dans le fichier XML. Il joue alors les actions et vérifient les assertions. Et cerise sur le gâteau, on peut spécifier, en plus des données à injecter dans la base de données en amont du test, le jeu de données étalon correspondant aux données que l'on doit trouver dans la base en fin de test. Seule contrainte : une balise <click name="CreateUserForm.validateButton" /> dans le fichier XML implique de positionner le nom du boutton sur lequel on veut cliquer avec la valeur indiquée. On retrouve donc dans le code de notre application, quelque part dans les sources de l'IHM l'instruction suivante: validateButton.setName("CreateUserForm.validateButton");. Cette contrainte peut aussi être vue comme la forme élémentaire de spécification logicielle...


On peut se demander si une telle implémentation, jouant avec les événements IHM, est possible en Delphi.


Intégration continue

Présentation

Un serveur d'IntégrationContinue est un logiciel idéalement installé sur une machine dédiée. Pour chacun des projets configurés, consulte, à une période définie, le serveur du GestionnaireDeVersion. S'il ne détecte aucun changement, il passe au projet suivant, ou il sommeille une période. S'il détecte une modification remontée sur le GestionnaireDeVersion, il exécute alors les actions définies par l'utilisateur. Ces actions peuvent être des scripts (des .bat par exemple sous Windows), ou mieux d, des cibles/goals définis via un outil de construction de projet tel que Ant ou Maven pour le monde Java.

Un exemple de séquence d'actions peut être (sachant qu'on ne passe à une action suivante que si la précédente est accomplie avec succès, sinon le cycle s'arrête en échec) :

  1. Obtenir la dernière version des sources (faire un "cvs checkout").
  2. Construire le projet.
  3. Jouer les tests unitaires.
  4. Construire la base de données.
  5. Jouer les tests release.
  6. Déposer le livrable du projet précédemment construit dans le répertoire de livraison.


CruiseControl

En utilisant un outil comme CruiseControl il est possible de spécifier une ligne de commande pour un cycle d'intégration. On peut donc envisager se spécifier l'appel au compilateur Delphi afin construire le projet.

Plus globalement, on peut envisager la séquence d'appels suivante (sachant qu'on ne passe à l'étape suivante que si l'étape courante est accomplie avec succès) :

  1. Construction du projet de test.
  2. Execution du projet de test.
  3. Construction du projet applicatif.
  4. Jeu des tests fonctionnels.
  5. Mise à disposition du projet applicatif.


Intégration avec DUnit

Lu sur gmane.comp.lang.delphi.dunit :

Question : CruiseControl works well with Junit, as that was the intention when it was created. JUnit creates reports logs (.xml), that CruiseControl can parse and display, using its custom reporting web-app. AFAIK, DUnit doesn't have any such report generation, so we'd likely have to write a custom report-writer to meet CruiseControl's expectations. Does anyone have any experience with generating reports from Dunit? We'd like to have fine-grain control over the testing reports of course, though as a start - just saying whether the MasterTestSuite (all tests) failed or succeeded would be nice.

Réponse : I have done that exact thing here at my work place. We use CruiseControl to build our Delphi products, and have written an XMLTestRunner. As was mentioned in another email, just write yourself a listener class that supports ITestListener. We took the bog easy approach and output the XML file in the same format that JUnit does. This way, the out-of-the box XSLT stylesheets can transform this XML output to the nice HTML as used on the CruiseControl web pages.


Dans la distribution dunit-9.2.1, on peut trouver le répertoire Contrib\XMLReporting qui contient le XMLTestRunner.pas nécessaire à la génération de rapport XML et donc permettre une pleine intégration à CruiseControl.


Conclusion

Au final, il apparait que le langage en lui même n'est pas plus important que l'IDE lui même et des "facilités" que ce dernier offre. Même s'il est vrai que ces fonctionalités sont directement liées aux caractéristiques du langage (telle que l'introspéction...)... D'où l'émergence de projets qui mettent l'accent sur l'environnement de développement comme xpdojo.org.


Ressources