Pourquoi JUnit ne fournit-il pas les méthodes assertNotEquals?

Est-ce que quelqu’un sait pourquoi JUnit 4 fournit des assertEquals(foo,bar) mais pas assertNotEqual(foo,bar) ?

Il fournit assertNotSame (correspondant à assertSame ) et assertFalse (correspondant à assertTrue ), il semble donc étrange qu’ils n’aient pas pris la peine d’ assertNotEqual .

Au fait, je sais que JUnit-addons fournit les méthodes que je recherche. Je demande juste par curiosité.

Je vous suggère d’utiliser les assertThat() plus assertThat() style assertThat() , qui peuvent facilement décrire toutes sortes de négations et créer automatiquement une description de ce que vous attendiez et de ce que vous avez obtenu si l’assertion échoue:

 assertThat(objectUnderTest, is(not(someOtherObject))); assertThat(objectUnderTest, not(someOtherObject)); assertThat(objectUnderTest, not(equalTo(someOtherObject))); 

Les trois options sont équivalentes, choisissez celle que vous trouvez la plus lisible.

Pour utiliser les noms simples des méthodes (et permettre à cette syntaxe de temps de fonctionner), vous avez besoin de ces importations:

 import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; 

Il y a un assertNotEquals dans JUnit 4.11: https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.11.md#improvements-to-assert-and-assume

 import static org.junit.Assert.assertNotEquals; 

Je me demande même. L’API d’Assert n’est pas très symésortingque; pour tester si les objects sont identiques, il fournit assertSame et assertNotSame .

Bien sûr, il n’est pas trop long d’écrire:

 assertFalse(foo.equals(bar)); 

Avec une telle assertion, la seule partie informative de la sortie est malheureusement le nom de la méthode de test, donc le message descriptif doit être formé séparément:

 Ssortingng msg = "Expected <" + foo + "> to be unequal to <" + bar +">"; assertFalse(msg, foo.equals(bar)); 

Cela est bien sûr tellement fastidieux qu’il est préférable de lancer son propre assertNotEqual . Heureusement à l’avenir, il fera peut-être partie de JUnit: JUnit issue 22

Je soutiens que l’absence d’assertNotEqual est en effet une asymésortinge et rend JUnit un peu moins apprenable. Gardez à l’esprit que c’est un bon exemple lorsque l’ajout d’une méthode diminue la complexité de l’API, du moins pour moi: Symmetry aide à gérer l’espace le plus grand. Je suppose que la raison de cette omission est peut-être que trop peu de personnes appellent la méthode. Pourtant, je me souviens d’une époque où même assertFalse n’existait pas; par conséquent, je m’attends à ce que la méthode soit éventuellement ajoutée, étant donné que ce n’est pas difficile; même si je reconnais qu’il existe de nombreuses solutions, même élégantes.

Je viens à cette fête assez tard mais j’ai trouvé que la forme:

 static void assertTrue(java.lang.Ssortingng message, boolean condition) 

peut être fait pour fonctionner pour la plupart des cas «pas égaux».

 int status = doSomething() ; // expected to return 123 assertTrue("doSomething() returned unexpected status", status != 123 ) ; 

La raison évidente pour laquelle les gens voulaient assertNotEquals () était de comparer les commandes intégrées sans avoir à les convertir en objects complets:

Exemple verbeux:

 .... assertThat(1, not(equalTo(Integer.valueOf(winningBidderId)))); .... 

contre.

 assertNotEqual(1, winningBidderId); 

Malheureusement, Eclipse n’incluant pas JUnit 4.11 par défaut, vous devez être verbeux.

Avertissement Je ne pense pas que le “1” doit être inclus dans un Integer.valueOf () mais comme je suis récemment revenu de .NET, ne comptez pas sur mon exactitude.

Je travaille sur JUnit dans l’environnement Java 8, en utilisant jUnit4.12

pour moi: le compilateur n’a pas pu trouver la méthode assertNotEquals, même quand j’utilisais
import org.junit.Assert;

J’ai donc changé
assertNotEquals("addb", ssortingng);
à
Assert.assertNotEquals("addb", ssortingng);

Donc, si vous rencontrez un problème concernant assertNotEqual non reconnu, changez-le en Assert.assertNotEquals(,); Cela devrait résoudre votre problème

Il est préférable d’utiliser Hamcrest pour les assertions négatives plutôt que d’assertFalse, car dans le premier, le rapport de test affichera un diff pour l’échec de l’assertion.

Si vous utilisez assertFalse, vous obtenez simplement un échec d’assertion dans le rapport. c’est-à-dire des informations perdues sur la cause de la panne.

Je suis totalement d’accord avec le sharepoint vue OP. Assert.assertFalse(expected.equals(actual)) n’est pas un moyen naturel d’exprimer une inégalité.
Mais je dirais que plus que Assert.assertEquals() , Assert.assertNotEquals() fonctionne mais n’est pas convivial pour documenter ce que le test affirme réellement et pour comprendre / déboguer lorsque l’assertion échoue.
Donc oui JUnit 4.11 et JUnit 5 fournissent Assert.assertNotEquals() ( Assertions.assertNotEquals() dans JUnit 5) mais j’évite vraiment de les utiliser.

Comme alternative, pour affirmer l’état d’un object, j’utilise généralement une API matcher qui fouille facilement l’état de l’object, qui documente clairement l’intention des assertions et qui est très conviviale pour comprendre la cause de l’échec de l’assertion.

Voici un exemple.
Supposons que je dispose d’une classe Animal que je veux tester avec la méthode createWithNewNameAndAge() , une méthode qui crée un nouvel object Animal en changeant son nom et son âge mais en conservant son aliment favori.
Supposons que j’utilise Assert.assertNotEquals() pour affirmer que les objects originaux et nouveaux sont différents.
Voici la classe Animal avec une implémentation imparfaite de createWithNewNameAndAge() :

 public class Animal { private Ssortingng name; private int age; private Ssortingng favoriteFood; public Animal(Ssortingng name, int age, Ssortingng favoriteFood) { this.name = name; this.age = age; this.favoriteFood = favoriteFood; } // Flawed implementation : use this.name and this.age to create the // new Animal instead of using the name and age parameters public Animal createWithNewNameAndAge(Ssortingng name, int age) { return new Animal(this.name, this.age, this.favoriteFood); } public Ssortingng getName() { return name; } public int getAge() { return age; } public Ssortingng getFavoriteFood() { return favoriteFood; } @Override public Ssortingng toSsortingng() { return "Animal [name=" + name + ", age=" + age + ", favoriteFood=" + favoriteFood + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((favoriteFood == null) ? 0 : favoriteFood.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (!(obj instanceof Animal)) return false; Animal other = (Animal) obj; return age == other.age && favoriteFood.equals(other.favoriteFood) && name.equals(other.name); } } 

JUnit 4.11+ (ou JUnit 5) à la fois en tant que testeur et outil d’assertion

 @Test void assertListNotEquals_JUnit_way() { Animal scoubi = new Animal("scoubi", 10, "hay"); Animal littleScoubi = scoubi.createWithNewNameAndAge("little scoubi", 1); Assert.assertNotEquals(scoubi, littleScoubi); } 

Le test échoue comme prévu, mais la cause fournie au développeur n’est vraiment pas utile. Il dit simplement que les valeurs doivent être différentes et afficher le résultat toSsortingng() invoqué sur le paramètre Animal actuel:

java.lang.AssertionError: Les valeurs doivent être différentes. Réel: Animal

[name = scoubi, age = 10, favoriteFood = hay]

à org.junit.Assert.fail (Assert.java:88)

Ok, les objects ne sont pas égaux. Mais où est le problème?
Quel champ n’est pas correctement évalué dans la méthode testée? Un ? Deux ? Tous ?
Pour le découvrir, vous devez creuser l’ createWithNewNameAndAge() / utiliser un débogueur alors que l’API de test serait beaucoup plus conviviale si elle faisait pour nous le différentiel attendu et obtenu.


JUnit 4.11 comme programme de test et une API de test Matcher comme outil d’assertion

Voici le même scénario de test mais qui utilise AssertJ (une excellente API de test matcher) pour faire l’affirmation de l’état Animal :

 import org.assertj.core.api.Assertions; @Test void assertListNotEquals_AssertJ() { Animal scoubi = new Animal("scoubi", 10, "hay"); Animal littleScoubi = scoubi.createWithNewNameAndAge("little scoubi", 1); Assertions.assertThat(littleScoubi) .extracting(Animal::getName, Animal::getAge, Animal::getFavoriteFood) .containsExactly("little scoubi", 1, "hay"); } 

Bien sûr, le test échoue toujours, mais cette fois, la raison est clairement indiquée:

java.lang.AssertionError:

Attendant:

<["scoubi", 10, "foin"]>

contenir exactement (et dans le même ordre):

<["petit scoubi", 1, "foin"]>

mais certains éléments n’ont pas été trouvés:

<["petit scoubi", 1]>

et d’autres n’étaient pas attendus:

<["scoubi", 10]>

au junit5.MyTest.assertListNotEquals_AssertJ (MyTest.java:26)

Nous pouvons lire que pour les Animal::getName, Animal::getAge, Animal::getFavoriteFood du Animal renvoyé, nous nous attendons à avoir ces valeurs:

 "little scoubi", 1, "hay" 

mais nous avons eu ces valeurs:

 "scoubi", 10, "hay" 

Nous soaps donc où enquêter: le name et l’ age ne sont pas correctement évalués. De plus, le fait de spécifier la valeur du hay dans l’affirmation de Animal::getFavoriteFood() permet également d’affirmer plus finement l’ Animal renvoyé. Nous voulons que les objects ne soient pas les mêmes pour certaines propriétés mais pas nécessairement pour toutes les propriétés.
Donc, l’utilisation d’une API matcher est beaucoup plus claire et flexible.

La cohérence de l’API Modulo, pourquoi JUnit n’a pas fourni assertNotEquals() est la même raison pour laquelle JUnit n’a jamais fourni de méthodes telles que

  • assertSsortingngMatchesTheRegex(regex, str) vs assertSsortingngDoesntMatchTheRegex(regex, str)
  • assertSsortingngBeginsWith(prefix, str) vs assertSsortingngDoesntBeginWith(prefix, str)

C’est-à-dire qu’il n’y a pas de fin à fournir des méthodes d’assertion spécifiques pour les types de choses que vous pourriez souhaiter dans votre logique d’assertion!

Mieux vaut fournir des primitives de test composables telles que equalTo(...) , is(...) , not(...) , regex(...) et laisser le programmeur les assembler pour plus de lisibilité et de sécurité.