commit 14851fbf4f824ac279ce76723b3afe9578857fb9 Author: Laureηt Date: Fri Dec 3 15:47:29 2021 +0100 fin de séance diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6b468b6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.class diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b1bba8a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.DS_Store": true, + "**/Thumbs.db": true, + "**/*.class": true + } +} \ No newline at end of file diff --git a/Apres.java b/Apres.java new file mode 100644 index 0000000..fe83ada --- /dev/null +++ b/Apres.java @@ -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 { + +} diff --git a/Assert.java b/Assert.java new file mode 100644 index 0000000..8e843ba --- /dev/null +++ b/Assert.java @@ -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(); + } + } + +} diff --git a/Avant.java b/Avant.java new file mode 100644 index 0000000..2af3ec2 --- /dev/null +++ b/Avant.java @@ -0,0 +1,7 @@ +import java.lang.annotation.*; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Avant { + +} diff --git a/CasLimitesTest.java b/CasLimitesTest.java new file mode 100644 index 0000000..12b3aae --- /dev/null +++ b/CasLimitesTest.java @@ -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 !"); + } + +} diff --git a/DeviseInvalideException.java b/DeviseInvalideException.java new file mode 100644 index 0000000..d950afd --- /dev/null +++ b/DeviseInvalideException.java @@ -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); + } + +} diff --git a/Echec.java b/Echec.java new file mode 100644 index 0000000..c8dcb55 --- /dev/null +++ b/Echec.java @@ -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); + } +} diff --git a/ErreurTest.java b/ErreurTest.java new file mode 100644 index 0000000..df26ea7 --- /dev/null +++ b/ErreurTest.java @@ -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); + } + +} diff --git a/FausseException.java b/FausseException.java new file mode 100644 index 0000000..7d99fc9 --- /dev/null +++ b/FausseException.java @@ -0,0 +1,3 @@ +public class FausseException extends Exception { + +} diff --git a/LanceurIndependant.java b/LanceurIndependant.java new file mode 100644 index 0000000..0cc31d4 --- /dev/null +++ b/LanceurIndependant.java @@ -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 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 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 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); + } +} diff --git a/Monnaie.java b/Monnaie.java new file mode 100644 index 0000000..b763cb9 --- /dev/null +++ b/Monnaie.java @@ -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 - - 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 - - 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); + } + } + +} diff --git a/MonnaieTest.java b/MonnaieTest.java new file mode 100644 index 0000000..89b20bc --- /dev/null +++ b/MonnaieTest.java @@ -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; + } + +} diff --git a/MonnaieTest2.java b/MonnaieTest2.java new file mode 100644 index 0000000..b834fb8 --- /dev/null +++ b/MonnaieTest2.java @@ -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. + } + +} diff --git a/UnTest.java b/UnTest.java new file mode 100644 index 0000000..3d42260 --- /dev/null +++ b/UnTest.java @@ -0,0 +1,9 @@ +import java.lang.annotation.*; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface UnTest { + boolean enabled() default true; + + Class expected() default FausseException.class; +}