Ok

En poursuivant votre navigation sur ce site, vous acceptez l'utilisation de cookies. Ces derniers assurent le bon fonctionnement de nos services. En savoir plus.

« Créer une application Grails de base | Page d'accueil | Modifier les templates afin d'avoir la normes Hydro-Québec »

02 février 2010

Tests unitaires d'une application grails simple

Tests unitaires

Afin de m'assurer dans le futur que les objets d'affaires remplissent bien leur contrat j'ai rédigé des tests pour les fonctionnalités attendue. Le gros de notre logique d'affaires est actuellement sous forme de contraintes. Les tests vont donc tourner autour de ces contraintes.

 

Les tests pour la classe Suivi sont assez simple car il s'agit d'une table simple avec peu de données.

 

class SuiviTests extends GroovyTestCase {

 

 

    void testUnSuiviMinimal() { 

            def p = new Projet(nom:"Un projet",dateProposition:new Date())

      def s = new Suivi(notes:"Test", projet:p)

      s.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs: "+s.errors,s.hasErrors()

            s.notes = ""

            s.validate()

      assertTrue "Il devrait  y avoir erreur: "+s.errors,s.hasErrors()

    } 

}

 

Celui pour la classe de marché est aussi simple:

 

class MarcheTests extends GroovyTestCase {

 

    void testUnMarcheMinimal() { 

      def m = new Marche(nom:"Test")

      m.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs: ",m.hasErrors()

            m.nom = ""

            m.validate()

      assertTrue "Il devrait  y avoir erreur: "+m.errors,m.hasErrors()

    } 

   

      void testNomUnique() {      

      def m = new Marche(nom:"Test")

            m.save()

      assertFalse "Il ne devrait pas y avoir d'erreurs: ",m.hasErrors()

 

      def m2 = new Marche(nom:"Test")

 

      m2.validate()

      assertTrue "Il devrait y avoir une erreur avec l'unicité du nom: ",m2.hasErrors()

    } 

 

      void testNomLongueur() {    

      def m1 = new Marche(nom:"T000000000T000000000T0000")

            m1.validate()

            assertFalse "Une longeur du nom de 25 char devrait être ok: ",m1.hasErrors()

            m1.nom="T000000000T000000000T000001"

            m1.validate()

      assertTrue "Il devrait y avoir une erreur sur la longeur du nom: "+m1.nom,m1.hasErrors()

    }

}

 

Celui pour la classe Personne est plus intéressant en particulier pour les tests sur le CIP:

 

class PersonneTests extends GroovyTestCase {

 

    void testUnPersonneMinimal() {      

      def p = new Personne(nom:"TestNom",prenom:"TestPrenom",cIP:"XX9999")

      p.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs: ",p.hasErrors()

    } 

 

      void testCIPUnique() {      

      def p = new Personne(nom:"TestNom",prenom:"TestPrenom",cIP:"XX9999")

            p.save()

      assertFalse "Il ne devrait pas y avoir d'erreurs: ",p.hasErrors()

 

      def p2 = new Personne(nom:"TestNomAutre",prenom:"TestPrenomAutre",cIP:"XX9999")

      p2.validate()

      assertTrue "Il devrait y avoir une erreur avec l'unicité du nom: ",p2.hasErrors()

    } 

     

      void testCIPValide() {      

      def p = new Personne(nom:"TestNom",prenom:"TestPrenom",cIP:"XX9999")

            p.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs: ",p.hasErrors()

            p.cIP = "aa0000"

            p.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs avec: " + p.cIP,p.hasErrors()

            p.cIP = "ZZ9999"

            p.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs avec: " + p.cIP,p.hasErrors()

      }

 

      void testCIPInValide() {    

      def p = new Personne(nom:"TestNom",prenom:"TestPrenom",cIP:"XX9999")

            p.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs: ",p.hasErrors()

            p.cIP = "aa000" // trop court

            p.validate()

      assertTrue "Il devrait y avoir erreurs avec cip court: " + p.cIP,p.hasErrors()

            p.cIP = "aa00000" // trop long

            p.validate()

      assertTrue "Il devrait y avoir erreurs avec cip long: " + p.cIP,p.hasErrors()

            p.cIP = "123456" // juste des chiffres

            p.validate()

      assertTrue "Il devrait y avoir erreurs avec juste des chiffres: " + p.cIP,p.hasErrors()

            p.cIP = "abcdef" // juste des lettres

            p.validate()

      assertTrue "Il devrait y avoir erreurs avec juste des lettres: " + p.cIP,p.hasErrors()

            p.cIP = "99ABCD" // inversion du pattern

            p.validate()

      assertTrue "Il devrait y avoir erreurs avec un autre pattern: " + p.cIP,p.hasErrors()

           

      }

}

 

Finalement pour la classe Projet, le cœur du système:

 

class ProjetTests extends GroovyTestCase {

 

    void testUnProjetMinimal() { 

      def p = new Projet(nom:"Test",dateProposition:new Date())

      p.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs: "+p.errors,p.hasErrors()

    } 

   

      void testNumeroValide() {   

      def p1 = new Projet(nom:"Test",dateProposition:new Date(),numero:1000)

      p1.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs: "+p1.errors,p1.hasErrors()

 

      def p2 = new Projet(nom:"Test",dateProposition:new Date(),numero:32767)

      p2.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs: "+p2.errors,p2.hasErrors()

 

      def p3 = new Projet(nom:"Test",dateProposition:new Date(),numero:9999)

      p3.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs: "+p3.errors,p3.hasErrors()

     

    } 

 

      void testNumeroInValide() { 

      def p = new Projet(nom:"Test",dateProposition:new Date(),numero:-1000)

      p.validate()

      assertTrue "Il devrait y avoir une erreur avec -1000: "+p.errors,p.hasErrors()

 

      def p2 = new Projet(nom:"Test",dateProposition:new Date(),numero:999)

      p2.validate()

      assertTrue "Il devrait y avoir une erreur avec 999: "+p2.errors,p2.hasErrors()

    } 

 

      void testNumeroUnique() {   

      def p1 = new Projet(nom:"Test",dateProposition:new Date(),numero:1000)

            p1.save()

      assertFalse "Il ne devrait pas y avoir d'erreurs: "+p1.errors,p1.hasErrors()

 

      def p2 = new Projet(nom:"Test",dateProposition:new Date(),numero:1000)

      p2.validate()

      assertTrue "Il devrait y avoir une erreur avec l'unicité du numéro: "+p2.errors,p2.hasErrors()

    } 

 

      void testNomUnique() {      

      def p1 = new Projet(nom:"Test",dateProposition:new Date())

            p1.save()

      assertFalse "Il ne devrait pas y avoir d'erreurs: "+p1.errors,p1.hasErrors()

 

      def p2 = new Projet(nom:"Test",dateProposition:new Date(),numero:1000)

      p2.validate()

      assertTrue "Il devrait y avoir une erreur avec l'unicité du nom: "+p2.errors,p2.hasErrors()

    } 

 

      void testNomLongueur() {    

      def p1 = new Projet(nom:"T000000000T000000000T000000000T000000000T000000000T000000000T000000000T000000000",dateProposition:new Date())

            p1.validate()

            assertFalse "Une longeur du nom de 80 char devrait être ok: "+p1.errors,p1.hasErrors()

            p1.nom="T000000000T000000000T000000000T000000000T000000000T000000000T000000000T0000000001"

            p1.validate()

      assertTrue "Il devrait y avoir une erreur sur la longeur du nom: "+p1.errors,p1.hasErrors()  

    }

 

      void testBudgetValide() {   

      def p = new Projet(nom:"Test",dateProposition:new Date(),budget:1f)

      p.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs avec budget de 1: "+p.errors,p.hasErrors()

            p.budget = 100000f

      p.validate()

      assertFalse "Il ne devrait pas y avoir d'erreurs avec budget de 100k: "+p.errors,p.hasErrors()

    } 

 

      void testBudgetInValide() { 

      def p = new Projet(nom:"Test",dateProposition:new Date(),budget:-1f)

      p.validate()

      assertTrue "Il devrait y avoir une erreur avec un budget négatif de -1: "+p.errors,p.hasErrors()

    }

 

      void testBudgetParDefaut() {      

      def p = new Projet(nom:"Test",dateProposition:new Date())

      assertEquals "j'attendais 20000",20000,p.budget

    }

}

 

En rédigeant ces tests et en les exécutants j'ai trouvé 3 bugs dans mon code. Le premier lors du test sur la contraintes sur la longueur du nom de projet, j'utilisais la contrainte maxLength au lieu de maxSize. Le second bug avait trait au regular expression que j'utilisais pour le CIP. J'avais "[a-zA-Z]2[0-9]6" au lieu de  "[a-zA-Z]{2}[0-9]{6}". Finalement il y avait une autre erreur dont je ne me souviens plus.

 

Les tests ont aussi été utile lorsque j'ai déployé l'application sur une autre machine. Quand j'ai fait Grails run-app, ça n'a pas compilé! Alors j'ai fais une Grails test-app et j'ai tout de suite vue quel test foirrait et la correction à pris 10 secondes. L'erreur était liée au fait que j'ai développé avec Grails 1.1 et que l'autre machine était sur 1.0.4.

 

Les tests produisent des rapports, dont voici un exemple.

grailsUnit1.jpg

 

 

 

 

 

 

 

Clickez pour une version plus grande

 

Et le détail :

grailsUni2.jpg

16:52 | Lien permanent | Commentaires (0) | Tags : grails