Exercices dirigés NFP121


Bluej : Utilisation

La classe Entier, méthode equals et hashCode, Entier.parseEntier, ...


Le projet BlueJ


En se basant sur la "documentation" de la classe Entier ci-dessous


QUESTION 1 : Proposez la classe Entier et les méthodes equals et hashCode, .

javadoc un extrait : Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes. Voir aussi https://en.wikipedia.org/wiki/Java_hashCode()
 

QUESTION 2 : La classe de tests unitaires doit être enrichie de tests de ces deux méthodes.

un extrait :

public class EntierTest extends junit.framework.TestCase{

public void testEquals(){
Entier e = new Entier(3);
Entier e1 = new Entier(2);

assertFalse(e.equals(e1)); // assertNotEquals n'existe pas e1.inc(); assertEquals(e,e1); assertEquals("deux objets égaux ==> leur hashCode sont égaux", e.hashCode(),e1.hashCode());

assertFalse(e.equals(null));

Entier e2 = new Entier(5);
assertEquals(e2,e2);
assertEquals(new Entier(7),new Entier(7));
assertEquals(new Entier(7).hashCode(),new Entier(7).hashCode());
}

public void testParseEntier(){
Entier e = Entier.parseEntier("3");
assertEquals(new Entier(3),e);
try{
Entier e1 = Entier.parseEntier("3x");
}catch(Exception exc){
assertTrue(exc instanceof NumberFormatException);
}
}

QUESTION 3 : Ajoutez de la méthode parseEntier ...public static Entier parseEntier(String s) throws NumberFormatException
                          cf. javadoc
Integer.parseInt

QUESTION 4 :  Réaliser un affichage sur la console d'une liste d'entiers, chaque entier saisi est incrémenté de 1



exemples de sortie attendues
a) pour

Main.main(new String[]{"2","8"});
nous obtenons
e.inc() : 3
e.inc() : 9

b) pour
Main.main(new String[]{"2","8","x","99"});
nous obtenons
e.inc() : 3
e.inc() : 9
x engendre une exception !
e.inc() : 100

 

Usage de la diapositive 52-53, complétez la classe ci dessous avec d'autres tests

http://jfod.cnam.fr/NFP121/supports/extras_NFP121_Junit3_Tests_Unitaires.pdf 

Outil de formatage html utilisé http://javavershtml.recoding.fr/

public class MainTest extends junit.framework.TestCase{

public void testSortieSurLaConsole() throws Exception{
String[] out = mainExec("Main",new String[]{"2","8"});
assertEquals(2, out.length);
assertTrue(out[0].endsWith("3"));
assertTrue(out[1].endsWith("9"));
}

public void testSortieSurLaConsoleAvecException() throws Exception{
String[] out = mainExec("Main",new String[]{"2","8","x","99"});
assertEquals(4, out.length);
assertTrue(out[0].endsWith("3"));
assertTrue(out[1].endsWith("9"));
assertTrue(out[2].toUpperCase().contains("EXCEPTION"));
assertTrue(out[3].endsWith("100"));
}


/** Obtention de l'affichage produit par l'exécution de la méthode main d'une classe.
* @param className le nom de la classe
* @param args les arguments de la ligne de commande
* @return le texte en tableau de lignes
* @throws une exception est levée si la classe est inconnue
*/
public static String[] mainExec(String className, String[] args)throws Exception{
java.io.PrintStream out = System.out;
String[] consoleOut = null; // ou new String[]{""}; try{
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
java.io.PrintStream ps = new java.io.PrintStream(baos);
Class<?> c = Class.forName(className);
System.setOut(ps);
c.getMethod("main",String[].class).invoke(null, new Object[]{args});
consoleOut = baos.toString().split(System.getProperty("line.separator"));
}finally{
System.setOut(out);
}
return consoleOut;
}
}

 

QUESTION 5 : Une IHM de test, l'affichage de cette IHM s'effectue en créant une instance de cette classe ou en exécutant la méthode main


- Modifiez cette IHM afin de pouvoir saisir un nombre entier, appel de Entier.parseEntier(data.getText());
  Avec un affichage en base 16 de la donnée entrée au clavier ou un point d'interrogation en cas de mauvaise saisie

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class IHMDeTest extends JFrame{ // Modele
private Entier e;

// Interface Humain Machine
private JButton enter;
private JTextField data,console;

public IHMDeTest(){ super("IHMDeTest");
this.e = new Entier(1);

JRootPane rootPane = this.getRootPane();
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());

this.console = new JTextField(e.toString());
Font bigFont = console.getFont().deriveFont(Font.PLAIN, 150f);
this.console.setFont(bigFont);
this.console.setHorizontalAlignment(JTextField.CENTER);
panel.add(console, BorderLayout.CENTER);

JPanel dialog = new JPanel();

this.data = new JTextField("1",10);
this.data.setHorizontalAlignment(JTextField.RIGHT);
dialog.add(data);
this.enter = new JButton("enter");
this.enter.addActionListener( new Enter());
dialog.add(enter);

panel.add(dialog, BorderLayout.PAGE_END);

add(panel); //rootPane.setContentPane(panel);
pack();
setVisible(true);
} private class Enter implements ActionListener{ public void actionPerformed(ActionEvent ae){ // à compléter
} } public static void main(String[] args){ new IHMDeTest();
} }

 

QUESTION 6 : Invariant de classe et fonction d'abstraction
http://jfod.cnam.fr/NFP121/supports/extras_NFP121_Junit3_Tests_Unitaires.pdf    Diapositives 42, 43, 44

Un extrait de la Page 99 du livre de Liskov et Guttag
 

        - L'invariant de classe repOk pour la classe Entier est simple
             nous n'avons à priori aucune contrainte sur la classe Entier alors
             boolean repOk(){ return true;} // ce ne sera pas tjs le cas..

        - Proposez une fonction d'abstraction la fonction af
              Integer af(){ return // à compléter;}
 

Proposez une nouvelle classe EntierLiskovRepOkAf qui implémente cette interface

 

public interface LiskovRepOkAf{
   
/** invariant de représentation.
     * Cet invariant est vrai avant et après l'exécution de toute
     * méthode de la classe, vrai à la sortie des constructeurs
     */
    public boolean repOk();
   
   

/** Fonction d'abstraction.
     *
     */
    public Object af();
   
   

//après le cours sur la généricité public <T> T af(); }

Une classe de tests à compléter

public class EntierLiskovTest extends junit.framework.TestCase{
 

//    i1  --- +1 ---> i2         abstrait //    ^                ^ //    |                | //    af               af --------------- //    |                | //    e1 --- inc()--> e2          concret      public void testInc(){
    EntierLiskovRepOkAf  e1 = new EntierLiskovRepOkAf(3);
    Integer i1 = e1.af();        // représentation abstraite i1     e1.inc();                            // inc dans le concret     i1 = i1 + 1;                          // +1 dans l'abstrait     EntierLiskovRepOkAf e2 = e1;  // afin de refléter le schéma     Integer i2 = e1.af();        // représentation abstraite i2     assertEquals(e2.af(),i2);   }     public void testDec(){
    EntierLiskovRepOkAf  e1 = new EntierLiskovRepOkAf(3);
    Integer i1 = e1.af();
    e1.dec();
    i1 = i1 -1;
    assertTrue(e1.af().equals(new Integer(i1)));
  }
 
 

public void testToString(){
    EntierLiskovRepOkAf  e1 = new EntierLiskovRepOkAf(33);
    Integer i1 = new Integer(33);
    assertEquals(e1.af().toString(),i1.toString());
    e1.inc();
    i1 = i1 +1;
    assertEquals(e1.af().toString(),i1.toString());
  }
 
 

public void testEquals(){
    EntierLiskovRepOkAf  e1 = new EntierLiskovRepOkAf(33);
    Integer i1 = new Integer(33);
    assertTrue(e1.af().equals(i1));
  }
}

 

 

Post-liminaire, Préparation du tp2, exécution et tests avec l'IHM au comportement attendu

1) téléchargement puis ouverture du tp2.jar

2) Exécution de l'IHM tp2> jar -jar ihm.jar
avec si nécessaire sous windows set PATH=répertoire_installation_de_bluej\bin;%PATH%


/* Une
idée...