IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Dotnet Discussion :

NUnit..qui l'eut cru :D


Sujet :

Dotnet

  1. #1
    Membre régulier Avatar de TheCaribouX
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2008
    Messages : 255
    Points : 122
    Points
    122
    Par défaut NUnit..qui l'eut cru :D
    Voila, rebonjour!

    n'y ayant apparemment pas de place prévue pour des messages à propos de NUnit, je vais tenter ici, quitte à ce que je me fasse déplacer...

    je débute totalement avec NUnit et j'ai un léger problème:
    j'ai une classe avec un constructeur genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public void maClasse(string s)
    {
     ...
     s.SubString(0,9);
     ...
    }
    et j'aimerais tester si, en créant une instance de cette classe avec un string trop petit, j'obtiens une exception.

    donc je fais un [Test] du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    [Test]
    [ExpectedException(typeof(ArgumentOutOfRangeException))]
    public void methodeTest()
    {
       maClasse mc = new maClasse("a");
    }
    Voila pour la partie code, maintenant mon (mes..) soucis:
    si je fais un try ... catch de l'exception en question dans le constructeur, l'exception n'est pas levée et donc nunit me dis que le test a "failed". Inversément si je catch pas l'exception, le test réussi. D'ou je me demande ce qui vaut mieux (à mon avis, il vaut mieux catcher l'exception et avori un test faux.. )

    ma seconde question est plus d'ordre général et va en faire rire plus d'un je pense... une fois que je catch l'exception, dans le constructeur, que dois-je faire? (terminer le prog, ignorer la demande, utiliser des paramêtres par defauts, ...)

    merci d'avoir lu tout ca...

  2. #2
    Expert éminent sénior

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Points : 12 465
    Points
    12 465
    Par défaut
    Salut,

    Inversément si je catch pas l'exception, le test réussi. D'ou je me demande ce qui vaut mieux (à mon avis, il vaut mieux catcher l'exception et avori un test faux.. )
    Hmmm....c'est un peu toi qui voit, en fait...

    Dans quel cas est-ce que tu vas appeler ta classe ?

    Est-ce que le fait que ta chaine s soit invalide peut casser ton programe (entrer des infos invalides dans une base, planter un calcul...) ? -> exception
    Est-ce que ta classe va potentiellement etre utilisee par quelqu'un d'autre que toi ? -> exception

    Est-ce que tu peux te baser sur le fait que ton utilisateur corrigera l'erreur ?

    une fois que je catch l'exception, dans le constructeur, que dois-je faire? (terminer le prog, ignorer la demande, utiliser des paramêtres par defauts, ...)
    Pareil que pour le precedent...Je te deconseille dans tout les cas de faire une classe qui va arreter ton programme en cas d'erreur, c'est de toute facon la responsabilite de ton interface utilisateur

    Si tu catches l'expression pour retourner une valeur nulle, ne catches pas l'exception...

    De toute facon, tu ne devrais pas avoir a catcher d'exception, tu devrais faire un test avant ton substring, pour verifier si ta chaine est suffisament longue, et envoyer toi-meme une exception ou ne pas appeler substringm, en fonction de ton choix...

  3. #3
    Membre régulier Avatar de TheCaribouX
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2008
    Messages : 255
    Points : 122
    Points
    122
    Par défaut
    Merci pour ta réponse!

    Est-ce que le fait que ta chaine s soit invalide peut casser ton programe (entrer des infos invalides dans une base, planter un calcul...) ? -> exception
    Oui ca peut bugger un afffichage

    Est-ce que ta classe va potentiellement etre utilisee par quelqu'un d'autre que toi ? -> exception
    Par définition oui...je pars un peu toujours de ce principe.

    -> exception

    De toute facon, tu ne devrais pas avoir a catcher d'exception, tu devrais faire un test avant ton substring, pour verifier si ta chaine est suffisament longue, et envoyer toi-meme une exception ou ne pas appeler substringm, en fonction de ton choix...
    Ca à mes yeux c'est bizzare, j'ai toujours pensé que les exceptions étaient la pour simplifier ce genre de choses.

    Donc si j'en conclus quelque chose:
    Si une erreur de construction peut corrompre le reste du processus, je leve des exceptions, ce qui en plus met une certaine sercurité au niveau d'un potentiel usage futur de mon code par quelqu'un d'autre de l'équipe.
    Une fois mon exception levée, j'affiche un message d'erreur et "reviens à l'étape précédant la construction de l'objet" <- mouais ca parait un peu vague , mais en gros ca parait pas mal?

    (merci en tout cas)

  4. #4
    Membre régulier Avatar de TheCaribouX
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2008
    Messages : 255
    Points : 122
    Points
    122
    Par défaut
    Je vviens de mettre en oeuvre ce que j'ai dis et un nouveau "problème" est apparu...

    En affichange un message (messageBox.show) lorsque je catch une erreur, le probleme est sur nunit, en effet, lorsque je lance les test, le message apparait et ne se ferme pas, donc, en soit, lorsque j'aurai beaucoup plus de tests, je perds completement le coté "lancement automatique de tests, dans le sens ou quelqu'un est obligé de fermer les messageBox manuellement..

  5. #5
    Expert éminent sénior

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Points : 12 465
    Points
    12 465
    Par défaut
    Revoit la separation de ton code et de ton IHM

    Si ta classe doit pouvoir etre facilement reutilisable, tu ne dois pas lui imposer de dependances externes (genre, une messagebox)

    Sinon, qu'est-ce qui va se passer si elle est appellee depuis une appli web?


    Ca à mes yeux c'est bizzare, j'ai toujours pensé que les exceptions étaient la pour simplifier ce genre de choses.
    Non, malheureux, surtout pas

    Une exception, c'est la pour rattraper une situation Exceptionnelle...

    Si ton client rentre que la moitie de son numero de secu, c'est a une regle metier de verifier que ton numero de secu est de la bonne longueur...

    Non seulement, utiliser des exceptions en lieu des regles metier, c'est mal, mais en plus, tu vas tuer les performances de ton application, car le framework n'est pas optimise pour remonter les exceptions...


    Fait un test, dans ton appli, fait ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for (int i = 0; i< 100000; i++){
    		try{
    			string s = t.Substring(0,9);
    		}catch{
    		}
    	}
    si t vaut "toto", le temps d'execution est de 7 secondes, si t vaut "autrechose", c'est instantane

    Dans certains cas, tu verras qu'une seule exception va bloquer ton code 1 ou deux secondes...

  6. #6
    Membre régulier Avatar de TheCaribouX
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2008
    Messages : 255
    Points : 122
    Points
    122
    Par défaut
    Citation Envoyé par pvialatte Voir le message
    Revoit la separation de ton code et de ton IHM

    Si ta classe doit pouvoir etre facilement reutilisable, tu ne dois pas lui imposer de dependances externes (genre, une messagebox)

    Sinon, qu'est-ce qui va se passer si elle est appellee depuis une appli web?
    du coup le mieux c'est de faire des writeline au niveau de la console? ca me parait pas tres "explicite" aux yeux de quelqu'un qui pourrait faire une erreur...

    Non, malheureux, surtout pas

    Une exception, c'est la pour rattraper une situation Exceptionnelle...

    Si ton client rentre que la moitie de son numero de secu, c'est a une regle metier de verifier que ton numero de secu est de la bonne longueur...

    Non seulement, utiliser des exceptions en lieu des regles metier, c'est mal, mais en plus, tu vas tuer les performances de ton application, car le framework n'est pas optimise pour remonter les exceptions...
    Pourtant dans un autre thread, un certain Franck Soriano que tu connais peut etre, m'a dit que

    Autre problème de la programme défensive : Si tu structures bien ton code, tu va très vite avoir beaucoup de petites méthodes qui s'appellent les unes les autres. Si chaque méthode commence par vérifer la cohérence de tous les paramètres à chaque fois, très vite le code "utile" de la méthode est noyé sous les vérifications et tout devient illisible... Les exceptions ont d'ailleurs été inventées pour améliorer ce problème.
    d'ou je me disais que... mais je te crois en terme de perf...



    Fait un test, dans ton appli, fait ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for (int i = 0; i< 100000; i++){
    		try{
    			string s = t.Substring(0,9);
    		}catch{
    		}
    	}
    si t vaut "toto", le temps d'execution est de 7 secondes, si t vaut "autrechose", c'est instantane

    Dans certains cas, tu verras qu'une seule exception va bloquer ton code 1 ou deux secondes...

  7. #7
    Romain Verdier
    Invité(e)
    Par défaut
    A part xUnit, je crois que tous les frameworks de tests unitaires sont déficients au niveau de la gestion des exceptions. L'assertion sous la forme d'un attribut de méthode est parfois un peu limitative.

    Dans ton exemple, il n'y a aucun problème, puisque ta méthode exécute une seule ligne de code.

    Je préfère souvent ajouter un bloc try/catch dans le corps de la méthode de test, qui encadre précisément le code devant lever l'exception. J'utilise ensuite Assert.Fail() pour faire échouer le test si l'exception n'est pas levée.

    C'était une parenthèse...

    Pour ton constructeur, utilise une guard clause :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public MaClasse(string s)
    {
        if (s.Length < 10)
        {
            throw new ArgumentException("'s' doit contenir au moins 10 caractères.");
        }
     
        //...
        s.Substring(0,9);
        //...
    }
    C'est légitime dans ce cas, et même indispensable. Comme le précise Philippe, une exception doit être levée lorsqu'une situation exceptionnelle survient. Ici, quelle qu'en soit la raison, si un appel à ton constructeur est fait avec un argument invalide, tu dois lever une exception.

    A ton code client de faire en sorte que ça n'arrive pas, en faisant par exemple intervenir en amont les règles de validations de ton domaine.

  8. #8
    Membre régulier Avatar de TheCaribouX
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2008
    Messages : 255
    Points : 122
    Points
    122
    Par défaut
    J'essaie d'appliquer, mais au final, je test la validité des arguments avant le début du constructeur et j'en arrive a avoir 2 fois plus de ligne de vérification que du constructeur lui-meme, ça a pas tendance à nuire à la lisibilité la guard clause?

  9. #9
    Romain Verdier
    Invité(e)
    Par défaut
    Citation Envoyé par TheCaribouX Voir le message
    J'essaie d'appliquer, mais au final, je test la validité des arguments avant le début du constructeur et j'en arrive a avoir 2 fois plus de ligne de vérification que du constructeur lui-meme, ça a pas tendance à nuire à la lisibilité la guard clause?
    Les guard clause ont justement pour but de rendre le code plus clair et auto commenté. Cela rejoint le concept des assertions et de la programmation par contrat. Elles ne sont pas obligatoires.

    Dans ton cas, tu peux laisser le constructeur sans guard clause, mais tu t'engages ainsi à ne jamais l'appeler avec de mauvais arguments. Si cela arrive tout de même, au lieu d'avoir une exception explicite qui indiquera à ton code client quelles sont les contraintes d'appel de ton constructeur, tu obtiendras celle qui sera levée par la méthode Substring.

    Il est intéressant d'ailleurs de constater que l'implémentation de cette dernière repose sur l'utilisation de guard clauses. Substring fait appel à la méthode suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    internal string InternalSubStringWithChecks(int startIndex, int length, bool fAlwaysCopy)
    {
        int num = this.Length;
        if (startIndex < 0)
        {
            throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
        }
        if (startIndex > num)
        {
            throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndexLargerThanLength"));
        }
        if (length < 0)
        {
            throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
        }
        if (startIndex > (num - length))
        {
            throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_IndexLength"));
        }
        if (length == 0)
        {
            return Empty;
        }
        return this.InternalSubString(startIndex, length, fAlwaysCopy);
    }
    A toi de voir quel niveau de consistance tu veux avoir dans ton modèle. Dans un cas aussi trivial, ce n'est peut être pas nécessaire, mais puisque tu poses la question ouvertement je te donne mon avis :')

  10. #10
    Membre régulier Avatar de TheCaribouX
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2008
    Messages : 255
    Points : 122
    Points
    122
    Par défaut
    Citation Envoyé par Romain Verdier Voir le message

    A toi de voir quel niveau de consistance tu veux avoir dans ton modèle. Dans un cas aussi trivial, ce n'est peut être pas nécessaire, mais puisque tu poses la question ouvertement je te donne mon avis :')
    Et je t'en remercie, c'est vraiment intéressant!

    Et donc une fois que je fais ce "throw new ..Exception", je suis sensé la catcher quelque part? autrement je reviens au problème du départ, je rencontre des exceptions qui terminent mon application.

  11. #11
    Expert éminent sénior

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Points : 12 465
    Points
    12 465
    Par défaut
    Citation Envoyé par TheCaribouX
    du coup le mieux c'est de faire des writeline au niveau de la console? ca me parait pas tres "explicite" aux yeux de quelqu'un qui pourrait faire une erreur...
    Naaaa...c'est a ton code d'interface utilisateur de gerer la communication entre l'utilisateur et ton programme, pas a ton constructeur de code...


    Citation Envoyé par TheCaribouX
    Et donc une fois que je fais ce "throw new ..Exception", je suis sensé la catcher quelque part?
    C'est l'appelant de ta methode qui va devoir catcher l'exception.

    Soit il la catche, et il se debrouille pour gerer l'exception et la remontee d'info au client, soit il ne la catche pas, et le programme crashe

    Apres, a un moment ou un autre, il faut bien la catcher, cette exception, mais idealement, tu devrais avoir un mecanisme pour ca cote interface de plus haut niveau...

    Et la, tu vas demander, mais si je dois la catcher de toute facon, pourquoi pas gerer au niveau du constructeur ???

    Et je te dirais que c'est pour des questions de reutilisation et de partage de ton code existant

  12. #12
    Membre régulier Avatar de TheCaribouX
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2008
    Messages : 255
    Points : 122
    Points
    122
    Par défaut
    Je commence a voir clair, merci d'anticiper mes questions

  13. #13
    Romain Verdier
    Invité(e)
    Par défaut
    C'est à toi de voir. Les guard clauses ne lèvent généralement pas des exceptions que l'on capture, ou plus exactement des exceptions qui peuvent être rattrapées. Ce sont des protections, qui ont pour but d'empêcher la corruption de l'état de ton modèle.

    Reprenons l'exemple de Substring. Cette méthode possède des guard clauses, et peut donc lever des exceptions. Ces dernières signalent les situations non désirées, et indiquent que la méthode ne peut strictement rien faire avec ces arguments invalides.

    On ne devrait jamais appeler Substring avec des arguments invalides, et il n'est clairement pas recommandé de "tester" son appel en l'encapsulant dans un bloc try/catch pour vérifier la validité des paramètres.

    Tout ça doit être fait en amont.

    Si tu obtiens une ArgumentException, c'est que quelque chose de grave s'est produit dans ton programme, et tu ne peux pas faire grand chose. C'est un peu comme les NullReferenceException.

    Ces exceptions sont souvent capturées au plus haut niveau de ton application, avant d'être journalisées. L'utilisateur peut (doit) être averti, l'application redémarrée, etc. Le fait d'avoir des guard clauses te permettra d'avoir des informations plus précises quant à l'origine du problème.

  14. #14
    Membre régulier Avatar de TheCaribouX
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2008
    Messages : 255
    Points : 122
    Points
    122
    Par défaut
    Ca y'est ca progresse vous dites quand vous en avez marre

    encore une question...

    imaginons (cas proche de la réalité) je programme en MVC, donc ma partie métier est séparée de la vue, pour rendre le code facilement réutilisable. Mon modèle throw des erreurs, je les catch dans l'interface afin d'en rendre compte à l'utilisateur.
    Dans un deuxieme temps, un autre développeur utilise ma partie métier mais veut développer une nouvelle interface, a-t'il un moyen d'etre mis au courant de toutes les exception qu'il va devoir gérer? (mis à part une doxygen bien faite)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. A ceux qui ont migré de VB6 vers VB.Net
    Par Fox dans le forum VB 6 et antérieur
    Réponses: 81
    Dernier message: 21/05/2008, 15h56
  2. Programme de boot qui passe la main à Windows
    Par Bob dans le forum Assembleur
    Réponses: 7
    Dernier message: 25/11/2002, 04h08
  3. Réponses: 3
    Dernier message: 22/07/2002, 15h19
  4. Créer une fenêtre flottante qui ne peut avoir le focus
    Par BestofMac dans le forum Composants VCL
    Réponses: 4
    Dernier message: 17/07/2002, 11h46
  5. Recherche programme qui convertit les chiffres arabes en nb
    Par oli57 dans le forum Algorithmes et structures de données
    Réponses: 5
    Dernier message: 15/06/2002, 04h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo