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 thehashCode
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 de l'applette de l'énoncé
console> appletviewer http://jfod.cnam.fr/progAvancee/tp2/tp2.html
avec si nécessaire sous windows set PATH=D:\BlueJ-315\jdk\bin;%PATH%
/* Une idée...