JUnitTest Infected: Programmers Love Writing Tests A little test, a little code, a little test, a little code…

Slides:



Advertisements
Présentations similaires
La programmation orientée objet avec Java L3-MIAGE Plan
Advertisements

PHP5 its a kind of magic. Chargement automatique function __autoload( $nom_classe ) { require_once('obj/'.$nom_classe.'.class.php'); } si on exécute le.
Cours n° 7 Standard Template Library II.
Gestion des événements (suite)
Introspection et Réflexion Manipulation dynamique de code Java.
SI3 MAM3 Hydro Nathan Cohen Igor Litovsky Christophe Papazian
Introduction à la Programmation Orientée Objet Retour sur les principaux concepts SI3 MAM3 Hydro Nathan Cohen
Séparation des préoccupations (c) 2004, Audrey Occello, LF8 MOC Seconde partie Un exemple de programmation orientée Aspect avec AspectJ.
CONTINUOUS TESTING Hakima Zidouri Informatique Réseau 3
MJ. BlinThe design patterns Design patterns Des modèles présentant des qualités particulières pour résoudre des problèmes fréquemment rencontrés en conception.
High Frequency Trading Introduction. Séminaires de 30 minutes, une fois par semaine (8 en tout) Sujets abordés – Définition dun algorithme et introduction.
Les entrées /sorties en Java François Bonneville
Connexion base de données
Chapitre IV Object, interfaces, classes imbriquées.
Injection de dépendances
Chapitre III Héritage (début)
Principes de programmation (suite)
BlueJ_XI 1 Java, les objets : tout de suite ! Gestion des erreurs : les exceptions Notes de cours associées au chapitre 11 tutorial BlueJ
JavaBeans Réalise par: EL KHADRAOUY TARIK AOUTIL SAFOWAN.
POO-L3 H. Fauconnier1 Chapitre IV 1. classe Object, clonage 2. interfaces 3. classes internes et imbriquées.
Faculté I&C, Claude Petitpierre, André Maurer 1 Java.
Langage Oriente Objet Cours 4.
Cours du 19 octobre. POO-L3 H. Fauconnier2 E) Constructeurs et héritage Le constructeurs ne sont pas des méthodes comme les autres: le redéfinition na.
La programmation objet Illustration de la POO en Pascal
Principes de programmation (suite)
Master 1 SIGLIS java Lecteur Stéphane Tallard Chapitre 4 – Structures de contrôle.
Introduction au paradigme objet Concepts importants surcharge (overload) redéfinition (override) Définition d’une classe Définition des attributs.
Le patron de conception « Strategy » Simon Durocher ( )
Programmation par Objets et Java
Langage Oriente Objet Cours 2.
Master 1 SIGLIS Java Lecteur Stéphane Tallard Chapitre 5 – Héritage, Interfaces et Listes génériques.
Introduction à la Programmation Orientée Objet Retour sur les principaux concepts SI3 MAM3 Hydro Nathan Cohen
JUnit Présentation complète de JUnit et « guide d’utilisation » en 13 transparents.
Introduction au paradigme orienté-objet (suite)
POO-L3 H. Fauconnier1 Supplément gratuit…. POO-L3 H. Fauconnier2 Entrée-sortie public static void main(String[] args) { // sortie avec printf ou double.
Design Pattern Memento. Principe : Enregistrer les changements d'états d'un objet Objectif : Pouvoir restituer les états précédents d'un objet.
Design Pattern: Decorator
Faculté I&C, Claude Petitpierre, André Maurer 1 Concepts dhéritage Héritage dimplémentation hasA Héritage de spécialisation isA.
Multi-Thread Jian-Yun Nie
Les tests Démo 10 : IFT3912.
1 IFT 6800 Atelier en Technologies dinformation Le langage de programmation Java chapitre 3 : Classes et Objects.
Chapitre 9 Les sous-programmes.
Badr Benmammar Formation Développeur Java Thread et Swing Badr Benmammar
Cours 11 Threads. Chapitre X threads threadPOO-L3 H. Fauconnier3 Threads threads: plusieurs activités qui coexistent et partagent des données exemples:
COURS DE PROGRAMMATION ORIENTEE OBJET :
COURS DE PROGRAMMATION ORIENTEE OBJET :
CSI1502 Principes fondamentaux en conception des logiciels Chapter 8: Gestion des exceptions.
Java, les objets : tout de suite ! Rassembler, grouper les objets
BlueJ_VI 1 Java, les objets : tout de suite ! Test, assertions, « vérification statique » Notes de cours associées au chapitre 6 Avec des assertions, utilisation.
99 Réutilisation du code grâce à l'héritage. 9-2 Objectifs À la fin de ce cours, vous serez capables de : Définir l'héritage Utiliser l'héritage pour.
Objectifs À la fin de ce cours, vous serez capables de :
Annexe 1 Tests unitaires d'applications Java avec JUNIT
LIFI-Java 2004 Séance du Mercredi 22 sept. Cours 3.
La notion de type revisitée en POO
Propriétés. Propriétés ► Les propriétés peuvent être visibles dans les environnements de scripts ► Les propriétés peuvent être accédées par programmation.
Factory Design Patterns. Contents Factory patterns: principesFactory patterns: principes The Factory Method patternThe Factory Method pattern The Abstract.
11/04/ L'héritage Cours 7 Cours 7.
Tutorat en bio-informatique
Les classes présenté par: RAHMOUNE RIME / ZEKRI SELMA.
Les classes et les objets Les données finales class A { … private final int n = 20 ; // la valeur de n est définie dans sa déclaration … } class A { public.
Schéma de conception Factory Method Exemple Sylvain Giroux.
Cours du 5 novembre.
Héritage H. Batatia. plan Notion (que signifie l’héritage) Ecriture en java Héritage multiple (interdit) Instanciation (partie propre et partie héritée)
Cours 4 (14 octobre) Héritage. Chapitre III Héritage.
Introduction à la programmation objet avec java
Héritage Conception par Objet et programmation Java
BlueJ_III 1 Java, les objets : tout de suite ! Interaction entre objets Notes de cours associées au chapitre 3 tutorial BlueJ
Introduction à l'orienté objet. Définition Le terme orienté objet siginifie que l'on organise le logiciel comme une collection d'objets organisée en graphe.
Transcription de la présentation:

JUnitTest Infected: Programmers Love Writing Tests A little test, a little code, a little test, a little code…

Enoncé du problème Portefeuille de devises Opérations arithmétiques avec diverses devises On ne peut pas simplement convertir une devise dans une autre Il nexiste pas un seul taux de conversion On peut vouloir comparer la valeur dun portefeuille au taux dhier avec celui au taux daujourdhui

Public class Money { private int fAmount; //ISO three letter abbreviation (USD, CHF, etc.). private String fCurrency; public Money(int amount, String currency){ fAmount= amount; fCurrency= currency; } public int amount() { return fAmount; } public String currency() { return fCurrency; } public Money add(Money m) { return new Money(amount()+m.amount(),currency()); } }

Addition dinstance de Money possédant la même devise, le montant de linstance résultante de Money est la somme des deux montants public class MoneyTest extends TestCase { //… public void testSimpleAdd() { Money m12CHF= new Money(12, "CHF"); // (1) Money m14CHF= new Money(14, "CHF"); Money expected= new Money(26, "CHF"); Money result= m12CHF.add(m14CHF); // (2) assertTrue(expected.equals(result)); // (3) } 1.Code qui crée les instance qui vont interagir pour le test. Le contexte du test est généralement appelé fixture.Code 2.Code qui active les instance de la fixture.Code 3.Code qui vérifie le résultat.Code

Deux instance de Money sont considérées égales si elles ont les mêmes montants et devises public void testEquals() { Money m12CHF= new Money(12, "CHF"); Money m14CHF= new Money(14, "CHF"); assertTrue(!m12CHF.equals(null)); assertEquals(m12CHF, m12CHF); assertEquals(m12CHF, new Money(12, "CHF")); // (1) assertTrue(!m12CHF.equals(m14CHF)); } assertTrue Déclenche un échec qui est loggé par JUnit lorsque largument nest pas vrai. assertEquals Test pour légalité à laide de la méthode « equals « Log les valeurs « textuelles » (printString) de chaque instance si elles diffèrent.

La méthode equals de la classe Money public boolean equals(Object anObject) { if (anObject instanceof Money){ Money aMoney= (Money)anObject; return aMoney.currency().equals(currency()) && amount() == aMoney.amount(); } return false; }

Common fixture Duplication de code pour mettre en place les tests. La méthode setUp Pour réutiliser le code commun de mise en place des tests. Placer les objets de la fixture dans des variables dinstance de la sous- classe de TestCase initialize them by overridding the setUp method. La méthode tearDown Opération symétrique de la méthode setUp La redéfinir pour nettoyer la fixture à la fin dun test. Chaque test sexécute dans sa propre fixture JUnit invoque setUp et tearDown pour chaque test Pour ne pas avoir deffet de bord entre les tests

Réécriture des tests – supprimer la duplication de code public class MoneyTest extends TestCase { private Money f12CHF; private Money f14CHF; protected void setUp() { f12CHF= new Money(12, "CHF"); f14CHF= new Money(14, "CHF"); } public void testEquals() { assertTrue(!f12CHF.equals(null)); assertEquals(f12CHF, f12CHF); assertEquals(f12CHF, new Money(12, "CHF")); assertTrue(!f12CHF.equals(f14CHF)); } public void testSimpleAdd() { Money expected= new Money(26, "CHF"); Money result= f12CHF.add(f14CHF); assertTrue(expected.equals(result)); } protected void tearDown() { f12CHF= null; f14CHF= null; }

Exécution dun test Statique Redéfinir la méthode runTest héritée de TestCase Invoquer le test unitaire désiré TestCase test= new MoneyTest("simple add"){ public void runTest() { testSimpleAdd(); } }; Dynamique Utiliser la réflexivité définie dans la méthode runTest TestCase test= new MoneyTest("testSimpleAdd");

Création dune instance de tests Anonymous inner class public void runTest( ){ testSimpleAdd(); } fName = «Simple add » TestCase public void runTest( ){ …… } runTest() MoneyTest

Création dune instance de tests fName = «testSimpleAdd » TestCase public void runTest( ){ trouver la méthode de sélecteur fName exécuter cette méthode } runTest() MoneyTest

Test suite TestSuite est un patron de conception Composite (Design Pattern) Un TestSuite peut exécuter une collection de tests. TestSuite et TestCase implémentent l interface Test qui définit les méthodes permettant déxécuter un test. Permet la création de suite de tests en composant arbitrairement les TestCases et les TestSuites. public static Test suite() { TestSuite suite= new TestSuite(); suite.addTest(new MoneyTest("testEquals")); suite.addTest(new MoneyTest("testSimpleAdd")); return suite; }

Static test suite public static Test suite() { TestSuite suite= new TestSuite(); suite.addTest(new MoneyTest("money equals") { protected void runTest() { testEquals(); } } ); suite.addTest( new MoneyTest("simple add") { protected void runTest() { testSimpleAdd(); } } ); return suite; }

Création dynamique de suites de tests Transmettre simplement la classe à tester à la classe TestSuite TestSuite extrait les méthodes de tests automatiquement public static Test suite() { return new TestSuite(MoneyTest.class); }

Opérations arithmétiques sur des devises différentes Il nexiste pas un taux de change unique Pour contourner ce problème, introduction de la classe MoneyBag qui diffère les conversions en fonction des taux de change. class MoneyBag { private Vector fMonies= new Vector(); MoneyBag(Money m1, Money m2) { appendMoney(m1); appendMoney(m2); } MoneyBag(Money bag[]) { for (int i= 0; i < bag.length; i++) appendMoney(bag[i]); } appendMoney Ajoute une instance de Money à la liste des Money s Soccupe de consolider les Money s possédant la même devise.

Tester MoneyBag protected void setUp() { f12CHF= new Money(12, "CHF"); f14CHF= new Money(14, "CHF"); f7USD= new Money( 7, "USD"); f21USD= new Money(21, "USD"); fMB1= new MoneyBag(f12CHF, f7USD); fMB2= new MoneyBag(f14CHF, f21USD); } public void testBagEquals() { assertTrue(!fMB1.equals(null)); assertEquals(fMB1, fMB1); assertTrue(!fMB1.equals(f12CHF)); assertTrue(!f12CHF.equals(fMB1)); assertTrue(!fMB1.equals(fMB2)); }

public Money add(Money m) { if (m.currency().equals(currency()) ) return new Money(amount()+m.amount(), currency()); return new MoneyBag(this, m); } Il existe maintenant deux représentations pour les Moneys : Money et MoneyBag Les cacher au niveau du code client. Introduire une interface IMoney implémentée par les deux représentations. interface IMoney { public abstract IMoney add(IMoney aMoney); //… }

Tests de laddition de IMoney public void testMixedSimpleAdd() { // [12 CHF] + [7 USD] == {[12 CHF][7 USD]} Money bag[]= { f12CHF, f7USD }; MoneyBag expected= new MoneyBag(bag); assertEquals(expected, f12CHF.add(f7USD)); } Les autres tests suivent le même patron: testBagSimpleAdd – addition dun MoneyBag à un Money simple testSimpleBagAdd - addition dun Money simple à un MoneyBag testBagBagAdd – addition de deux MoneyBags

Suite de tests pour MoneyBag public static Test suite() { TestSuite suite= new TestSuite(); suite.addTest(new MoneyTest("testMoneyEquals")); suite.addTest(new MoneyTest("testBagEquals")); suite.addTest(new MoneyTest("testSimpleAdd")); suite.addTest(new MoneyTest("testMixedSimpleAdd")); suite.addTest(new MoneyTest("testBagSimpleAdd")); suite.addTest(new MoneyTest("testSimpleBagAdd")); suite.addTest(new MoneyTest("testBagBagAdd")); return suite; }

Implémentation de laddition Le défi de cette implémentation est de gérer les diverses combinaisons de Money et MoneyBag. Le patron de conception « Double dispatch » solution élégante à ce problème (Visitor DP). Lidée derrière le double dispatch est dutiliser un appel supplémentaire pour découvrir le type des arguments impliqués. Transmettre au paramètre un message dont le (nouveau) nom est le nom de la méthode originale suivi du nom de la classe du destinataire original. class Money implements IMoney { public IMoney add(IMoney m) { return m.addMoney(this); } //… } class MoneyBag implements IMoney { public IMoney add(IMoney m) { return m.addMoneyBag(this); } //… }

Implémentation du double dispatch dans Money class Money implements IMoney { public IMoney add(IMoney m) { return m.addMoney(this); } public IMoney addMoney(Money m) { if (m.currency().equals(currency()) ) return new Money( amount()+m.amount(), currency()); return new MoneyBag(this, m); } public IMoney addMoneyBag(MoneyBag s) { return s.addMoney(this); }

Implémentation du double dispatch dans MoneyBag class MoneyBag implements IMoney { public IMoney add(IMoney m) { return m.addMoneyBag(this); } public IMoney addMoney(Money m) { return new MoneyBag(m, this); } public IMoney addMoneyBag(MoneyBag s) { return new MoneyBag(s, this); }

Test de la simplification de MoneyBag public void testSimplify() { // {[12 CHF][7 USD]} + [-12 CHF] == [7 USD] Money expected= new Money(7, "USD"); assertEquals( expected, fMB1.add(new Money(-12, "CHF"))); } // … Test fails

Implémentation de la simplification dans MoneyBag class MoneyBag implements IMoney { public IMoney add(IMoney m) { return m.addMoneyBag(this); } public IMoney addMoney(Money m) { return new MoneyBag(m, this).simplify(); } public IMoney addMoneyBag(MoneyBag s) { return new MoneyBag(s, this).simplify(); } private IMoney simplify() { if (fMonies.size() == 1) return (IMoney)fMonies.firstElement(); return this; }

Conclusion Un peu de tests, un peu de code, un peu de tests, un peu de code… Capturer lintention dans les tests Le code des tests est comme le code du modèle Il fonctionne mieux sil est bien factorisé. Garder les vieux tests fonctionnels est aussi important que décrire de nouveaux tests qui fonctionnent. Lorsque lon a envie décrire un énoncé « print » ou une instruction de déverminage, écrire un test à la place JUnit : une manière de tester qui demande un faible investissement Plus rapide, plus productif, plus prévisible et moins de stress. Il devient possible de refactoriser plus agressivement une fois que les tests sont disponibles.

Interface commune pour les classes Money et MoneyBag interface IMoney { public abstract IMoney add(IMoney m); /** * implementing double dispatch */ IMoney addMoney(Money m); IMoney addMoneyBag(MoneyBag s); public abstract boolean isNull(); public abstract IMoney multiply(int factor); public abstract IMoney negate(); public abstract IMoney subtract(IMoney m); }

Références Erich Gamma and Kent Beck, JUnitTest Infected: Programmers Love Writing Tests, Java Report, July 1998, Volume 3, Number 7 testing.htm