Bonjour, je suis en train de me faire violence et apprendre à utiliser un
outil de tests unitaires, Cactus en l'occurence.
Je compte mettre en oeuvre autant de tests qu'il y a de formulaires dans
mon application.
1) Est-il normal que j'ai à modifier un DAO pour permettre l'exécution
d'un test.
Par exemple, j'ai du créer cette méthode :
public Collection findWithCriteria(String criteria)
Dans le code ci-dessus, il y a plusieurs choses qui me dérangent :
- si le code échoue pour une raison Y (mise au point du test), il laisse
la base de donnée dans un état incohérent
Plus généralement je fais référence à des données statiques (la catégorie
parente dont l'ID est 1 : FAUX si la base est vide, le titre de la catégorie
doit être 'TESTCASE_CHILDCAT', etc
Quelle technique/principe puis-je mettre en oeuvre pour éviter d'écrire
un test qui :
a) laisserait passer une erreur
b) ne produit pas d'erreurs par lui même
Bonjour, je suis en train de me faire violence et apprendre à utiliser un
outil de tests unitaires, Cactus en l'occurence.
Je compte mettre en oeuvre autant de tests qu'il y a de formulaires dans
mon application.
1) Est-il normal que j'ai à modifier un DAO pour permettre l'exécution
d'un test.
Par exemple, j'ai du créer cette méthode :
public Collection findWithCriteria(String criteria)
Dans le code ci-dessus, il y a plusieurs choses qui me dérangent :
- si le code échoue pour une raison Y (mise au point du test), il laisse
la base de donnée dans un état incohérent
Plus généralement je fais référence à des données statiques (la catégorie
parente dont l'ID est 1 : FAUX si la base est vide, le titre de la catégorie
doit être 'TESTCASE_CHILDCAT', etc
Quelle technique/principe puis-je mettre en oeuvre pour éviter d'écrire
un test qui :
a) laisserait passer une erreur
b) ne produit pas d'erreurs par lui même
Bonjour, je suis en train de me faire violence et apprendre à utiliser un
outil de tests unitaires, Cactus en l'occurence.
Je compte mettre en oeuvre autant de tests qu'il y a de formulaires dans
mon application.
1) Est-il normal que j'ai à modifier un DAO pour permettre l'exécution
d'un test.
Par exemple, j'ai du créer cette méthode :
public Collection findWithCriteria(String criteria)
Dans le code ci-dessus, il y a plusieurs choses qui me dérangent :
- si le code échoue pour une raison Y (mise au point du test), il laisse
la base de donnée dans un état incohérent
Plus généralement je fais référence à des données statiques (la catégorie
parente dont l'ID est 1 : FAUX si la base est vide, le titre de la catégorie
doit être 'TESTCASE_CHILDCAT', etc
Quelle technique/principe puis-je mettre en oeuvre pour éviter d'écrire
un test qui :
a) laisserait passer une erreur
b) ne produit pas d'erreurs par lui même
Bon, c'est peut être pas trop clair ce que je raconte ;-)
Bon, c'est peut être pas trop clair ce que je raconte ;-)
Bon, c'est peut être pas trop clair ce que je raconte ;-)
Je connais JUnit mieux que je ne connais Cactus, mais je vais essayer
d'esquisser la solution... Ce n'est pas une astuce technique, c'est une
question de bien comprendre la logique du test unitaire.
Le problème est le suivant: setUp ne devrait pas avoir à "communiquer"
avec beginXXX.
Pour bien comprendre, il faut connaître un peu la philosophie de JUnit,
qui est l'ancètre de Cactus. Dans JUnit, il y a pour chaque classe de
test un seul setUp et un seul tearDown. Chaque classe de test doit
contenir des tests qui peuvent être déroulés dans le même contexte de
test (on dit aussi "fixture"). Donc, quand on veut des setUp()
différents, on va tout simplement créer une nouvelle classe de test,
parce que ça signifie qu'on est dans un contexte différent. Ce
contexte, on est censé le connaître.
C'est seulement parce que "l'astuce" de JUnit qui consiste à exécuter,
dans une même classe de test, toutes les méthodes testXXX() (via la
reflection de Java), rend la vie très (trop) simple qu'on a tendance à
faire l'équation "cas de test" = "méthode de test". En fait un cas de
test est une classe de test. Pour un seul cas de test tu peux avoir N
méthodes de test qui testent des comportements divers *dans un contexte
donné* et ce contexte est supposé invariable. JUnit est fait comme ça,
c'est peut-être un mauvais choix, mais c'est un choix qui fait partie
de sa conception et Cactus reprend ce choix.
La doc de Cactus n'est pas dans le vrai quand elle dit que beginXXX est
"l'équivalent côté client" de setUp(). Les méthodes beginXXX() *font
partie du test*, puisqu'elles précisent le comportement du client dans
un cas d'utilisation donné. Tu pourrais tout faire dans testXXX().
Alors que les méthodes setUp() ne font jamais partie du test, tout ce
qu'elles font c'est établir un contexte pour le test.
Dans ton exemple, "le contexte" c'est la base de données dans un état
bien précis, avec des catégories dont les propriétés sont connues.
Donc, dans setUp() il faudrait recréer systématiquement les *mêmes*
données en
base, de sorte que l'identifiant de la catégorie parente reste constant
d'un test à l'autre. Par exemple, utilise un INSERT qui spécifie la clé
primaire. Et du coup, tu vas coder "en dur" l'identifiant en question
dans tes beginXXX.
Je connais JUnit mieux que je ne connais Cactus, mais je vais essayer
d'esquisser la solution... Ce n'est pas une astuce technique, c'est une
question de bien comprendre la logique du test unitaire.
Le problème est le suivant: setUp ne devrait pas avoir à "communiquer"
avec beginXXX.
Pour bien comprendre, il faut connaître un peu la philosophie de JUnit,
qui est l'ancètre de Cactus. Dans JUnit, il y a pour chaque classe de
test un seul setUp et un seul tearDown. Chaque classe de test doit
contenir des tests qui peuvent être déroulés dans le même contexte de
test (on dit aussi "fixture"). Donc, quand on veut des setUp()
différents, on va tout simplement créer une nouvelle classe de test,
parce que ça signifie qu'on est dans un contexte différent. Ce
contexte, on est censé le connaître.
C'est seulement parce que "l'astuce" de JUnit qui consiste à exécuter,
dans une même classe de test, toutes les méthodes testXXX() (via la
reflection de Java), rend la vie très (trop) simple qu'on a tendance à
faire l'équation "cas de test" = "méthode de test". En fait un cas de
test est une classe de test. Pour un seul cas de test tu peux avoir N
méthodes de test qui testent des comportements divers *dans un contexte
donné* et ce contexte est supposé invariable. JUnit est fait comme ça,
c'est peut-être un mauvais choix, mais c'est un choix qui fait partie
de sa conception et Cactus reprend ce choix.
La doc de Cactus n'est pas dans le vrai quand elle dit que beginXXX est
"l'équivalent côté client" de setUp(). Les méthodes beginXXX() *font
partie du test*, puisqu'elles précisent le comportement du client dans
un cas d'utilisation donné. Tu pourrais tout faire dans testXXX().
Alors que les méthodes setUp() ne font jamais partie du test, tout ce
qu'elles font c'est établir un contexte pour le test.
Dans ton exemple, "le contexte" c'est la base de données dans un état
bien précis, avec des catégories dont les propriétés sont connues.
Donc, dans setUp() il faudrait recréer systématiquement les *mêmes*
données en
base, de sorte que l'identifiant de la catégorie parente reste constant
d'un test à l'autre. Par exemple, utilise un INSERT qui spécifie la clé
primaire. Et du coup, tu vas coder "en dur" l'identifiant en question
dans tes beginXXX.
Je connais JUnit mieux que je ne connais Cactus, mais je vais essayer
d'esquisser la solution... Ce n'est pas une astuce technique, c'est une
question de bien comprendre la logique du test unitaire.
Le problème est le suivant: setUp ne devrait pas avoir à "communiquer"
avec beginXXX.
Pour bien comprendre, il faut connaître un peu la philosophie de JUnit,
qui est l'ancètre de Cactus. Dans JUnit, il y a pour chaque classe de
test un seul setUp et un seul tearDown. Chaque classe de test doit
contenir des tests qui peuvent être déroulés dans le même contexte de
test (on dit aussi "fixture"). Donc, quand on veut des setUp()
différents, on va tout simplement créer une nouvelle classe de test,
parce que ça signifie qu'on est dans un contexte différent. Ce
contexte, on est censé le connaître.
C'est seulement parce que "l'astuce" de JUnit qui consiste à exécuter,
dans une même classe de test, toutes les méthodes testXXX() (via la
reflection de Java), rend la vie très (trop) simple qu'on a tendance à
faire l'équation "cas de test" = "méthode de test". En fait un cas de
test est une classe de test. Pour un seul cas de test tu peux avoir N
méthodes de test qui testent des comportements divers *dans un contexte
donné* et ce contexte est supposé invariable. JUnit est fait comme ça,
c'est peut-être un mauvais choix, mais c'est un choix qui fait partie
de sa conception et Cactus reprend ce choix.
La doc de Cactus n'est pas dans le vrai quand elle dit que beginXXX est
"l'équivalent côté client" de setUp(). Les méthodes beginXXX() *font
partie du test*, puisqu'elles précisent le comportement du client dans
un cas d'utilisation donné. Tu pourrais tout faire dans testXXX().
Alors que les méthodes setUp() ne font jamais partie du test, tout ce
qu'elles font c'est établir un contexte pour le test.
Dans ton exemple, "le contexte" c'est la base de données dans un état
bien précis, avec des catégories dont les propriétés sont connues.
Donc, dans setUp() il faudrait recréer systématiquement les *mêmes*
données en
base, de sorte que l'identifiant de la catégorie parente reste constant
d'un test à l'autre. Par exemple, utilise un INSERT qui spécifie la clé
primaire. Et du coup, tu vas coder "en dur" l'identifiant en question
dans tes beginXXX.
C'est ce que je me disais mais (sauf erreur de ma part), Cactus appelle
beginXXX avant setUp ! C'est une des choses que j'ai vraiment du mal à
comprendre.
C'est ce que je me disais mais (sauf erreur de ma part), Cactus appelle
beginXXX avant setUp ! C'est une des choses que j'ai vraiment du mal à
comprendre.
C'est ce que je me disais mais (sauf erreur de ma part), Cactus appelle
beginXXX avant setUp ! C'est une des choses que j'ai vraiment du mal à
comprendre.
C'est ce que je me disais mais (sauf erreur de ma part), Cactus appelle
beginXXX avant setUp ! C'est une des choses que j'ai vraiment du mal à
comprendre.
C'est vrai que dans ton cas ça semble compliquer inutilement les choses.
Maintenant, si tu y réfléchis, c'est une conséquence logique de la
situation: Cactus simule un client et un serveur. Comment veux-tu que le
client "connaisse" l'identifiant d'un objet qui est stocké en base côté
serveur ? Que setUp() soit appelé avant ou après ne change rien à
l'affaire - tu aurais quand même besoin de faire passer ton identifiant
par un canal "illogique" puisqu'il n'existe pas dans la situation qu'on
est censé tester. (Normalement, ton client a récupéré, via un premier
formulaire, donc après une première requête GET, l'identifiant d'une
catégorie qui est déjà créée.)
Le problème vient de ce que tu créées ta catégorie via "makePersistent"
en laissant Hibernate générer l'identifiant. Ton test installe donc une
situation "aléatoire" - tu ne peux pas prédire à l'avance quel sera
l'identifiant généré par makePersistent. (Est-ce que c'est correct ?) Or
un test unitaire doit installer une situation parfaitement connue.
A la place, peux-tu spécifier l'identifiant au moment de rendre l'objet
persistant ? Le peu que je connais d'Hibernate me laisse penser que
c'est possible, via setId - je peux me tromper. (Sinon, peux-tu utiliser
des INSERT ?) Cela te permettrait de spécifier à l'avance l'identifiant
de la catégorie.
Bref, c'est à peu près comme ça que c'est censé se passer:
public void setUp() throws Exception
{
beginDAO();
// On commence par créer et sauvegarder une catégorie
Category cat = new Category();
cat.setId(99);
cat.setTitle(ROOTCAT_SIGNATURE);
categoryDAO.makePersistent(cat);
endDAO();
}
public void beginModifyCategory(WebRequest wr) throws Exception
{
setupAuthCommonParameters(wr);
// On prépare le form post
wr.addParameter("action","modcat");
wr.addParameter("postback","true");
wr.addParameter("category.id",99);
wr.addParameter("category.title",EDITED);
}
C'est ce que je me disais mais (sauf erreur de ma part), Cactus appelle
beginXXX avant setUp ! C'est une des choses que j'ai vraiment du mal à
comprendre.
C'est vrai que dans ton cas ça semble compliquer inutilement les choses.
Maintenant, si tu y réfléchis, c'est une conséquence logique de la
situation: Cactus simule un client et un serveur. Comment veux-tu que le
client "connaisse" l'identifiant d'un objet qui est stocké en base côté
serveur ? Que setUp() soit appelé avant ou après ne change rien à
l'affaire - tu aurais quand même besoin de faire passer ton identifiant
par un canal "illogique" puisqu'il n'existe pas dans la situation qu'on
est censé tester. (Normalement, ton client a récupéré, via un premier
formulaire, donc après une première requête GET, l'identifiant d'une
catégorie qui est déjà créée.)
Le problème vient de ce que tu créées ta catégorie via "makePersistent"
en laissant Hibernate générer l'identifiant. Ton test installe donc une
situation "aléatoire" - tu ne peux pas prédire à l'avance quel sera
l'identifiant généré par makePersistent. (Est-ce que c'est correct ?) Or
un test unitaire doit installer une situation parfaitement connue.
A la place, peux-tu spécifier l'identifiant au moment de rendre l'objet
persistant ? Le peu que je connais d'Hibernate me laisse penser que
c'est possible, via setId - je peux me tromper. (Sinon, peux-tu utiliser
des INSERT ?) Cela te permettrait de spécifier à l'avance l'identifiant
de la catégorie.
Bref, c'est à peu près comme ça que c'est censé se passer:
public void setUp() throws Exception
{
beginDAO();
// On commence par créer et sauvegarder une catégorie
Category cat = new Category();
cat.setId(99);
cat.setTitle(ROOTCAT_SIGNATURE);
categoryDAO.makePersistent(cat);
endDAO();
}
public void beginModifyCategory(WebRequest wr) throws Exception
{
setupAuthCommonParameters(wr);
// On prépare le form post
wr.addParameter("action","modcat");
wr.addParameter("postback","true");
wr.addParameter("category.id",99);
wr.addParameter("category.title",EDITED);
}
C'est ce que je me disais mais (sauf erreur de ma part), Cactus appelle
beginXXX avant setUp ! C'est une des choses que j'ai vraiment du mal à
comprendre.
C'est vrai que dans ton cas ça semble compliquer inutilement les choses.
Maintenant, si tu y réfléchis, c'est une conséquence logique de la
situation: Cactus simule un client et un serveur. Comment veux-tu que le
client "connaisse" l'identifiant d'un objet qui est stocké en base côté
serveur ? Que setUp() soit appelé avant ou après ne change rien à
l'affaire - tu aurais quand même besoin de faire passer ton identifiant
par un canal "illogique" puisqu'il n'existe pas dans la situation qu'on
est censé tester. (Normalement, ton client a récupéré, via un premier
formulaire, donc après une première requête GET, l'identifiant d'une
catégorie qui est déjà créée.)
Le problème vient de ce que tu créées ta catégorie via "makePersistent"
en laissant Hibernate générer l'identifiant. Ton test installe donc une
situation "aléatoire" - tu ne peux pas prédire à l'avance quel sera
l'identifiant généré par makePersistent. (Est-ce que c'est correct ?) Or
un test unitaire doit installer une situation parfaitement connue.
A la place, peux-tu spécifier l'identifiant au moment de rendre l'objet
persistant ? Le peu que je connais d'Hibernate me laisse penser que
c'est possible, via setId - je peux me tromper. (Sinon, peux-tu utiliser
des INSERT ?) Cela te permettrait de spécifier à l'avance l'identifiant
de la catégorie.
Bref, c'est à peu près comme ça que c'est censé se passer:
public void setUp() throws Exception
{
beginDAO();
// On commence par créer et sauvegarder une catégorie
Category cat = new Category();
cat.setId(99);
cat.setTitle(ROOTCAT_SIGNATURE);
categoryDAO.makePersistent(cat);
endDAO();
}
public void beginModifyCategory(WebRequest wr) throws Exception
{
setupAuthCommonParameters(wr);
// On prépare le form post
wr.addParameter("action","modcat");
wr.addParameter("postback","true");
wr.addParameter("category.id",99);
wr.addParameter("category.title",EDITED);
}
Je vais essayer d'aller dans ce sens... Rhâa faut vraiment s'accrocher pour
mettre en pratique de bonnes méthodes ! Je suppose que c'est au début qu'on
patinne, après on en retire les bénéfices.
Je vais essayer d'aller dans ce sens... Rhâa faut vraiment s'accrocher pour
mettre en pratique de bonnes méthodes ! Je suppose que c'est au début qu'on
patinne, après on en retire les bénéfices.
Je vais essayer d'aller dans ce sens... Rhâa faut vraiment s'accrocher pour
mettre en pratique de bonnes méthodes ! Je suppose que c'est au début qu'on
patinne, après on en retire les bénéfices.