Junit4: Amélioration : prise en charge de BigDecimal pour assertEquals()

Créé le 25 mars 2010  ·  27Commentaires  ·  Source: junit-team/junit4

L'utilisation de JUnit pour tester les valeurs BigDecimal est toujours un point sensible. C'est parce que BigDecimal considère la précision en utilisant equals() mais l'ignore dans compareTo(). La meilleure façon de gérer cela serait une nouvelle méthode assertEquals qui permet d'évaluer éventuellement la précision. Vous pouvez également ajouter une méthode alternative qui accepte un message :

public static void assertEquals (BigDecimal attendu, BigDecimal réel, précision booléenneMatters) {
if (precisionMatters) {
Assert.assertEquals(attendu, réel);
} autre {
Assert.assertEquals(0, attendu.compareTo(réel));
}
}

feature

Commentaire le plus utile

Avez-vous essayé d'utiliser comparesEqualTo ?

Tous les 27 commentaires

Ce serait une chose facile à assembler comme une fourchette ou un patch ; Je serais prêt à le faire si nécessaire.

Je préfère avoir une assertion assertNumericallyEqualTo qu'un indicateur booléen passé à assertEquals.

C'est un bon nom. Je le raccourcirais en assertNumericallyEquals().

Bien que je sois d'accord avec le sentiment, je ne suis pas sûr qu'avoir une autre méthode d'assertion avec un nom différent aidera vraiment à dissiper la confusion, en particulier parmi les personnes qui ne sont absolument pas conscientes de la différence ou qui n'ont pas vraiment rencontré le problème elles-mêmes. Je veux dire, si je n'avais pas lu ce numéro, j'aurais utilisé assertEquals() pour BigDecimal . Dans le cas général, cela fonctionnerait en fait comme annoncé - cela fonctionnerait exactement comme BigDecimal#equals() fonctionne. Je dirais même que c'est une bonne chose - cela oblige quelqu'un à se rendre compte que BigDecimal#equals() compare à la fois la valeur et l'échelle alors peut-être que ce n'était pas ce qu'ils essayaient d'accomplir - bien que, dans d'autres cas, je le postule _est_. Je veux dire, dans certains cas, nous voulons vérifier que la valeur réelle renvoyée par une méthode est _exactement_ 'égale' à la valeur attendue (pas seulement logiquement/numériquement égale). En d'autres termes : qu'est-ce que assertNumericallyEquals() fournit (à part la brièveté) que assertEquals(0, actual.compareTo(expected)) n'apporte pas ? Personnellement, je créerais probablement un matcher Hamcrest et irais assertThat(actual, isNumericallyEqualTo(expected)) si j'en avais besoin assez souvent - de plus, je peux être utilisé partout où les matchers Hamcrest peuvent être utilisés (validation des données, entre autres).

Désolé pour la pesée tardive, mais mon opinion personnelle est proche de celle d'Alistair.

En d'autres termes : qu'est-ce que assertNumericallyEquals() fournit (à part la brièveté) que assertEquals(0, actual.compareTo(expected)) n'apporte pas ?

Communique l'intention plus clairement ? L'approche du matcher hamcrest me convient.

Geoffroy,

Êtes-vous en train de dire que vous êtes d'accord pour écrire ce matcher pour votre propre projet, ou que vous souhaitez qu'il soit livré avec hamcrest ? Ou JUnit, mais pas hamcrest ?

Tout ou partie de ce qui précède - la plupart des projets que j'écris finissent par avoir des matchers hamcrest personnalisés. Avoir des cas courants couverts par Hamcrest et/ou JUnit fait gagner un peu de temps, mais cela n'a pas non plus été un cas très courant pour moi.

Un petit point sur les messages d'erreur moins utiles. Je viens de convertir mes appels Assert.assertEquals en Assert.assertTrue après avoir rencontré des échecs lors de la comparaison de BigDecimals avec Assert.assertEquals. Bien sûr, maintenant mes tests échouent avec une sorte d'erreur "test booléen échoué", sans me dire quelles étaient les valeurs. De la même manière, assertEquals(0, actual.compareTo(expected)) enregistrerait, par exemple, "attendu 0 mais obtenu : 1" alors qu'un message d'erreur beaucoup plus utile proviendrait de assertNumericallyEquals(réel, attendu) serait "attendu 12.45 mais obtenu : 123" (les valeurs réelles des arguments 'réel' et 'attendu').

http://www.bssd.eu/blog/?p=113 fait également une lecture intéressante.

assertEquivalent de https://github.com/KentBeck/junit/pull/228 devrait résoudre ce problème.

Merci dsaff. Ce travail a l'air super. Je ne l'ai jamais fait auparavant, cela signifie-t-il que je dois récupérer la source junit, fusionner moi-même cette demande d'extraction et créer une version personnalisée ?

D'après l'aide sur http://help.github.com/send-pull-requests/, il semble que je devrais :

git clone https://github.com/KentBeck/junit.git
cd junt

puis ajoutez une télécommande pour la demande d'extraction, puis extrayez, fusionnez ou faites les deux.

Étant donné que cela semble être une demande d'extraction, c'est-à-dire non officielle, est-il judicieux de l'utiliser dans une application ? Y a-t-il une chance que cela moisisse en dehors de l'unité principale et que j'aurai des problèmes pour envoyer mon code à d'autres, pour qui il ne sera pas construit ?

Neekfenwick,

Oui, vous êtes sur la bonne voie pour savoir comment le faire maintenant. J'ai l'intention de fusionner ce pull dans la branche 4.10, mais l'auteur d'origine a eu du mal à fusionner le statut git. Si vous avez le temps de rendre service au monde, vous pouvez bifurquer le repo KentBeck, tout fusionner et émettre une pull request contre la branche 4.10, afin que ce soit plus facile pour tout le monde (si ça a l'air populaire, je pourrais même faire tourner jusqu'à parfois un pot de prévisualisation 4.10).

Je n'ai vraiment jamais fait cela auparavant :) J'ai donc forké le repo et cloné [email protected] :neekfenwick/junit.git sur ma machine locale (j'ai déjà un compte github et des clés ssh configurés), et j'ai ajouté une télécommande pour le dépôt à partir duquel je l'ai forcée :

git remote add upstream https://github.com/KentBeck/junit.git

Juste pour faire bonne mesure, j'ai créé une branche pour pouvoir fusionner la demande d'extraction ailleurs que HEAD :

git branch merge_pullreq_228
git checkout merge_pullreq_228

Maintenant, les documents que je peux trouver disent "maintenant fusionnez la demande d'extraction dans votre branche". Je peux voir les commits pour pull 228 sur https://github.com/KentBeck/junit/pull/228/commits mais je ne peux pas les fusionner :

[neek junit (merge_pullreq_228)]$ git merge 57b49344
fatal: '57b49344' does not point to a commit

Étant donné que la demande d'extraction n'est pas destinée à mon propre dépôt/branche, je ne peux pas utiliser les outils de fusion dans l'interface graphique Web github (AFAIK).

Ai-je raison de penser que vous voulez que je fusionne les 7 commits dans ma propre branche et que je fasse construire/passer les tests unitaires ? Pourriez-vous expliquer quoi faire pour fusionner l'un de ces commits pour me mettre sur la bonne voie ?

D'accord, vous ne pouvez pas utiliser les outils de fusion Web. Ce que je crois devrait fonctionner est de:

git remote ajouter leet3lite https://github.com/leet3lite/junit.git

Et puis depuis votre agence, appelez

git pull leet3lite maître

Malheureusement, j'oublie généralement une chose lorsque je décris comment utiliser git "par téléphone", alors faites-moi savoir si cela fonctionne pour vous.

Ah je vois, je n'ai pas besoin de fusionner chacun de ces commits. La branche master de leet3lite les a déjà dessus, et c'est le fait de fusionner ce travail dans le master d'origine qui est le problème.

Il semble y avoir des conflits de fusion entre cette branche et HEAD. Je suppose que c'est tout l'intérêt de cet exercice.

[neek junit (merge_pullreq_228)]$ git remote add leet3lite https://github.com/leet3lite/junit.git
[neek junit (merge_pullreq_228)]$ git pull leet3lite master
remote: Counting objects: 100, done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 85 (delta 34), reused 77 (delta 26)
Unpacking objects: 100% (85/85), done.
From https://github.com/leet3lite/junit
 * branch            master     -> FETCH_HEAD
Auto-merging acknowledgements.txt
CONFLICT (content): Merge conflict in acknowledgements.txt
Auto-merging src/main/java/org/junit/Assert.java
Auto-merging src/test/java/org/junit/tests/AllTests.java
CONFLICT (content): Merge conflict in src/test/java/org/junit/tests/AllTests.java
Automatic merge failed; fix conflicts and then commit the result.
[neek junit (merge_pullreq_228|MERGING)]$ 

Si cela vous semble raisonnable, j'envisagerai de continuer demain. Presque minuit ici.

On dirait que vous êtes au bon endroit. accusés de réception.txt et AllTests.java sont beaucoup touchés, généralement juste avec des ajouts, donc l'opération de fusion est probablement un simple acte d'inclure toutes les lignes ajoutées sur les deux chemins.

Merci beaucoup d'avoir poussé cela vers l'avant.

Je pense que cela a été corrigé il y a 2 ans.

dsaff --Non ...?

Pas en 4.11 ;( j'ai aussi besoin de cette fonctionnalité

La discussion sur assertEquivalent() passée au #228 et après cela, je pense qu'elle est passée au #376 où nous avons décidé que vraiment Hamcrest devrait résoudre ce problème.

@junit-team/junit-committers des objections à ce que je ferme ceci?

Aucune objection de ma part.

Oups, clic freudien. :-) Aucune objection ici.

D'accord. Fermeture alors.

Je ne pense pas que l'utilisation du matcher hamcrest résout ce problème. Par exemple ce code :

   assertThat(product.getRating(), is(equalTo(new BigDecimal("2.3"))));

produira ce résultat :

Expected: is <2.3>
     but: was <2.30000>

Je pense que junit ou hamcrest a toujours besoin isNumericEquivalent méthode

Avez-vous essayé d'utiliser comparesEqualTo ?

Oui, comparesEqualTo fonctionne réellement. Merci.

Voici un aide-mémoire que j'ai créé il y a quelque temps :
http://www.marcphilipp.de/blog/2013/01/02/hamcrest-quick-reference/

Cette page vous a été utile?
0 / 5 - 0 notes