Merge remote-tracking branch 'tp4/master'

This commit is contained in:
Laureηt 2023-04-22 17:31:07 +02:00
commit be75b61655
Signed by: Laurent
SSH key fingerprint: SHA256:kZEpW8cMJ54PDeCvOhzreNr4FSh6R13CMGH/POoO8DI
16 changed files with 394 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.class

11
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,11 @@
{
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"**/*.class": true
}
}

10
Apres.java Normal file
View file

@ -0,0 +1,10 @@
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Apres {
}

19
Assert.java Normal file
View file

@ -0,0 +1,19 @@
/** La classe Assert définit des méthodes de vérification. Pour l'instant, la
* seule méthode de vérification est assertTrue mais d'autres pourraient être
* définies (voir JUnit).
*
* @author Xavier Crégut
* @version $Revision: 1.1 $
*/
abstract public class Assert {
/** Vérifier que la condition est vraie.
* @param condition la condition à vérifier
*/
static public void assertTrue(boolean condition) {
if (! condition) {
throw new Echec();
}
}
}

7
Avant.java Normal file
View file

@ -0,0 +1,7 @@
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Avant {
}

35
CasLimitesTest.java Normal file
View file

@ -0,0 +1,35 @@
/** Tester quelques cas limites.
* @author Xavier Crégut
* @version $Revision$
*/
public class CasLimitesTest {
public void testOK() {
// OK.
}
private void testMethodePrivee() {
throw new RuntimeException("Une méthode privée n'est pas un test !");
}
protected void testMethodeProtegee() {
throw new RuntimeException("Une méthode protected n'est pas un test !");
}
void testMethodePaquetage() {
throw new RuntimeException("Une méthode de droit d'accès paquetage n'est pas un test !");
}
public static void testMethodeDeClasse() {
throw new RuntimeException("Une méthode de classe n'est pas un test !");
}
public void testAvecParametre(int a) {
throw new RuntimeException("Une méthode avec des paramètres n'est pas un test !");
}
public void testAvecParametre2(int a) {
throw new RuntimeException("Une méthode avec des paramètres n'est pas un test !");
}
}

View file

@ -0,0 +1,13 @@
/** L'exception DeviseInvalideException indique des devises incompatibles sur
* des opérations entre monnaies.
*
* @author Xavier Crégut
* @version $Revision: 1.1 $
*/
public class DeviseInvalideException extends Exception {
public DeviseInvalideException(String message) {
super(message);
}
}

12
Echec.java Normal file
View file

@ -0,0 +1,12 @@
/** L'exception Echec permet de signaler l'erreur fonctionnelle d'un test.
* @author Xavier Crégut
* @version $Revision: 1.1 $
*/
public class Echec extends Error {
public Echec() {
super("condition non vérifiée");
}
public Echec(String message) {
super(message);
}
}

17
ErreurTest.java Normal file
View file

@ -0,0 +1,17 @@
/** ErreurTest est un programme de test qui définit trois méthodes de test
* dont une provoque une erreur.
*/
public class ErreurTest {
public void tester1() {
}
public void tester2() {
Assert.assertTrue(false);
}
public void tester3() {
Assert.assertTrue(true);
}
}

3
FausseException.java Normal file
View file

@ -0,0 +1,3 @@
public class FausseException extends Exception {
}

147
LanceurIndependant.java Normal file
View file

@ -0,0 +1,147 @@
import java.lang.reflect.*;
import java.util.*;
import java.lang.annotation.*;
/**
* L'objectif est de faire un lanceur simple sans utiliser toutes les clases de
* notre architecture JUnit. Il permet juste de valider la compréhension de
* l'introspection en Java.
*/
public class LanceurIndependant {
private int nbTestsLances;
private int nbErreurs;
private int nbEchecs;
private List<Throwable> erreurs = new ArrayList<>();
public LanceurIndependant(String... nomsClasses) {
System.out.println();
// Lancer les tests pour chaque classe
for (String nom : nomsClasses) {
try {
System.out.println(nom + " : ");
this.testerUneClasse(nom);
System.out.println();
} catch (ClassNotFoundException e) {
System.out.println("Classe inconnue !");
} catch (Exception e) {
System.out.println("Problème : " + e);
e.printStackTrace();
}
}
// Afficher les erreurs
for (Throwable e : erreurs) {
System.out.println();
e.printStackTrace();
}
// Afficher un bilan
System.out.printf("%d tests lancés dont %d échecs et %d erreurs.", nbTestsLances, nbEchecs, nbErreurs);
}
public int getNbTests() {
return this.nbTestsLances;
}
public int getNbErreurs() {
return this.nbErreurs;
}
public int getNbEchecs() {
return this.nbEchecs;
}
private void testerUneClasse(String nomClasse)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException,
IllegalArgumentException, InvocationTargetException, SecurityException {
// Récupérer la classe
Class<?> classe = Class.forName(nomClasse);
// Récupérer les méthodes "preparer" et "nettoyer"
Method preparer = null;
Method nettoyer = null;
for (Method method : classe.getMethods()) {
if (method.isAnnotationPresent(Avant.class)) {
preparer = method;
break;
}
}
for (Method method : classe.getMethods()) {
if (method.isAnnotationPresent(Apres.class)) {
nettoyer = method;
break;
}
}
// Instancier l'objet qui sera le récepteur des tests
// Object objet = classe.newInstance();
Object objet = classe.getDeclaredConstructor().newInstance();
// Exécuter les méthods de test
Method[] methods = classe.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(UnTest.class)) {
if (method.getAnnotation(UnTest.class).enabled()) {
this.nbTestsLances++;
if (preparer != null) {
preparer.invoke(objet);
}
Class<? extends Throwable> exep = method.getAnnotation(UnTest.class).expected();
try {
if (exep != FausseException.class) {
System.out.println("exep != FausseException.class");
try {
method.invoke(objet);
System.out.println(method.getName() + " : echec");
this.nbEchecs++;
} catch (InvocationTargetException e) {
Class<? extends Throwable> exep2 = method.getAnnotation(UnTest.class).expected();
if (e.getCause().getClass().isAssignableFrom(exep)) {
System.out.println(method.getName() + " : success");
} else {
System.out.println(method.getName() + " : erreur");
this.erreurs.add(e);
this.nbErreurs++;
}
}
} else {
try {
method.invoke(objet);
System.out.println(method.getName() + " : success");
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Echec) {
System.out.println(method.getName() + " : echec");
this.erreurs.add(e);
this.nbEchecs++;
} else {
System.out.println(method.getName() + " : erreur");
this.erreurs.add(e);
this.nbErreurs++;
}
}
}
} catch (java.lang.IllegalArgumentException e) {
System.out.println(method.getName() + " : erreur, pas de test avec arguments");
this.nbErreurs++;
System.out.println("d");
}
if (nettoyer != null) {
nettoyer.invoke(objet);
}
}
}
}
}
public static void main(String... args) {
new LanceurIndependant(args);
}
}

59
Monnaie.java Normal file
View file

@ -0,0 +1,59 @@
/** La classe Monnaie est caractérisée par une valeur et une devise. Deux
* monnaies peuvent être ajoutées ou retranchées.
*
* @author Xavier Crégut
* @version $Revision: 1.1 $
*/
public class Monnaie {
private int valeur;
private String devise;
/** Initialiser une monnaie à partir de sa valeur de et sa devise.
* @param valeur valeur de la monnaie
* @param devise devise de la monnaie
*/
public Monnaie(int valeur, String devise) {
this.valeur = valeur;
this.devise = devise;
}
/** Obtenir la valeur de cette monnaie.
* @param la valeur de cette monnaie
*/
public int getValeur() {
return this.valeur;
}
/** Obtenir la devise de cette monnaie.
* @param la devise de cette monnaie
*/
public String getDevise() {
return this.devise;
}
/** Ajouter une autre monnaie à cette devise.
* @param autre l'autre devise
* @depend - <send> - DeviseInvalideException
*/
public void ajouter(Monnaie autre) throws DeviseInvalideException {
verifierMemesDevises(autre);
this.valeur += autre.valeur;
}
/** Retrancher une autre monnaie à cette devise.
* @param autre l'autre devise
* @depend - <send> - DeviseInvalideException
*/
public void retrancher(Monnaie autre) throws DeviseInvalideException {
verifierMemesDevises(autre);
this.valeur -= autre.valeur;
}
private void verifierMemesDevises(Monnaie autre) throws DeviseInvalideException {
if (! this.devise.equals(autre.devise)) {
throw new DeviseInvalideException("Devises incompatibles : "
+ this.devise + " et " + autre.devise);
}
}
}

39
MonnaieTest.java Normal file
View file

@ -0,0 +1,39 @@
/** Classe regroupant les tests unitaires de la classe Monnaie. */
public class MonnaieTest {
protected Monnaie m1;
protected Monnaie m2;
protected Monnaie m3;
@Avant
public void debut() {
this.m1 = new Monnaie(5, "euro");
this.m2 = new Monnaie(7, "euro");
}
@UnTest(enabled = false)
public void ajouter() throws DeviseInvalideException {
m1.ajouter(m2);
Assert.assertTrue(m1.getValeur() == 12);
}
@UnTest
public void retrancher() throws DeviseInvalideException {
m1.retrancher(m2);
Assert.assertTrue(m1.getValeur() == -2);
}
@UnTest(expected = NullPointerException.class)
public void retrancher2() throws DeviseInvalideException {
m1.retrancher(m2);
m3.ajouter(m1);
Assert.assertTrue(m1.getValeur() == 1234567890);
}
@Apres
public void rwwwwit() {
this.m1 = null;
this.m2 = null;
}
}

12
MonnaieTest2.java Normal file
View file

@ -0,0 +1,12 @@
/** MonnaieTest2 : Vérifier que les méthodes de test de la superclasse sont bien
* prises en compte !
* @author Xavier Crégut
* @version $Revision$
*/
public class MonnaieTest2 extends MonnaieTest {
public void testSupplementaire() {
// OK.
}
}

9
UnTest.java Normal file
View file

@ -0,0 +1,9 @@
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UnTest {
boolean enabled() default true;
Class<? extends Throwable> expected() default FausseException.class;
}

BIN
sujet.pdf Normal file

Binary file not shown.