java - unitaria - qué anotación indica que un método será una prueba
¿Por qué JUnit no proporciona métodos assertNotEquals? (10)
Es mejor usar el Hamcrest para afirmaciones negativas en lugar de assertFalse ya que en el primer informe de prueba mostrará una diferencia para el fallo de la afirmación.
Si usa assertFalse, solo obtiene un error de aserción en el informe. Es decir, la información perdida en la causa de la falla.
¿Alguien sabe por qué JUnit 4 proporciona assertEquals(foo,bar)
pero no assertNotEqual(foo,bar)
?
Proporciona assertNotSame
(correspondiente a assertSame
) y assertFalse
(correspondiente a assertTrue
), por lo que parece extraño que no se molestaran en incluir assertNotEqual
.
Por cierto, sé que JUnit-addons proporciona los métodos que estoy buscando. Solo pregunto por curiosidad.
Estoy totalmente de acuerdo con el punto de vista OP. Assert.assertFalse(expected.equals(actual))
no es una forma natural de expresar una desigualdad.
Pero diría que más allá de Assert.assertEquals()
, Assert.assertNotEquals()
funciona, pero no es fácil de usar para documentar lo que realmente afirma la prueba y para entender / depurar cuando falla la aserción.
Así que sí, JUnit 4.11 y JUnit 5 proporcionan Assert.assertNotEquals()
( Assertions.assertNotEquals()
en JUnit 5) pero realmente evito usarlos.
Como alternativa, para afirmar el estado de un objeto, generalmente uso una API de emparejamiento que indaga fácilmente en el estado del objeto, que documenta claramente la intención de las aserciones y que es muy fácil de usar para comprender la causa de la falla de la aserción.
Aquí hay un ejemplo.
Supongamos que tengo una clase Animal que quiero probar el método createWithNewNameAndAge()
, un método que crea un nuevo objeto Animal cambiando su nombre y su edad pero manteniendo su comida favorita.
Supongamos que uso Assert.assertNotEquals()
para afirmar que el original y los nuevos objetos son diferentes.
Aquí está la clase Animal con una implementación defectuosa de createWithNewNameAndAge()
:
public class Animal {
private String name;
private int age;
private String favoriteFood;
public Animal(String name, int age, String 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(String name, int age) {
return new Animal(this.name, this.age, this.favoriteFood);
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getFavoriteFood() {
return favoriteFood;
}
@Override
public String toString() {
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+ (o JUnit 5) como guía de prueba y herramienta de aserción
@Test
void assertListNotEquals_JUnit_way() {
Animal scoubi = new Animal("scoubi", 10, "hay");
Animal littleScoubi = scoubi.createWithNewNameAndAge("little scoubi", 1);
Assert.assertNotEquals(scoubi, littleScoubi);
}
La prueba falla como se esperaba, pero la causa proporcionada al desarrollador realmente no es útil. Simplemente dice que los valores deben ser diferentes y generar el resultado toString()
invocado en el parámetro Animal
real:
java.lang.AssertionError: Los valores deben ser diferentes. Actual: Animal
[nombre = scoubi, edad = 10, favorito Comida = heno]
en org.junit.Assert.fail (Assert.java:88)
Ok, los objetos no son iguales. Pero ¿dónde está el problema?
¿Qué campo no se valora correctamente en el método probado? Uno ? Dos? Todos ellos ?
Para descubrirlo, tiene que profundizar en la implementación de createWithNewNameAndAge()
/ usar un depurador, mientras que la API de prueba sería mucho más amigable si hiciera para nosotros el diferencial entre lo que se espera y lo que se obtiene.
JUnit 4.11 como corredor de prueba y una API Matcher de prueba como herramienta de aserción
Aquí, el mismo escenario de prueba, pero que utiliza AssertJ (una excelente API de comparación de pruebas) para hacer la afirmación del estado 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");
}
Por supuesto, la prueba sigue fallando, pero esta vez la razón está claramente establecida:
java.lang.AssertionError:
Esperando
<["scoubi", 10, "heno"]>
para contener exactamente (y en el mismo orden):
<["pequeño scoubi", 1, "heno"]>
pero no se encontraron algunos elementos:
<["pequeño scoubi", 1]>
y otros no se esperaban:
<["scoubi", 10]>
en junit5.MyTest.assertListNotEquals_AssertJ (MyTest.java:26)
Podemos leer que para los valores de Animal::getName, Animal::getAge, Animal::getFavoriteFood
del animal devuelto, esperamos tener estos valores:
"little scoubi", 1, "hay"
Pero hemos tenido estos valores:
"scoubi", 10, "hay"
Así que sabemos dónde investigar: name
y age
no se valoran correctamente. Además, el hecho de especificar el valor del hay
en la afirmación de Animal::getFavoriteFood()
también permite afirmar con más precisión el Animal
devuelto. Queremos que los objetos no sean iguales para algunas propiedades, pero no necesariamente para todas las propiedades.
Así que definitivamente, usar una API de comparación es mucho más claro y flexible.
Estoy trabajando en JUnit en entorno java 8, usando jUnit4.12
para mí: el compilador no pudo encontrar el método assertNotEquals, incluso cuando lo usé
import org.junit.Assert;
Así que cambié
assertNotEquals("addb", string);
a
Assert.assertNotEquals("addb", string);
Entonces, si está enfrentando un problema relacionado con assertNotEqual
no reconocido, cámbielo a Assert.assertNotEquals(,);
debería resolver tu problema
Hay un assertNotEquals
en 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;
La consistencia de Modulo API, por qué JUnit no proporcionó assertNotEquals()
es la misma razón por la que JUnit nunca proporcionó métodos como
-
assertStringMatchesTheRegex(regex, str)
vs.assertStringDoesntMatchTheRegex(regex, str)
-
assertStringBeginsWith(prefix, str)
contraassertStringDoesntBeginWith(prefix, str)
es decir, ¡no hay fin de proporcionar métodos de aserción específicos para los tipos de cosas que podría desear en su lógica de aserción!
Mucho mejor proporcionar primitivas de prueba equalTo(...)
como equalTo(...)
, is(...)
, not(...)
, regex(...)
y dejar que el programador las junte para una mayor legibilidad y cordura.
La razón obvia por la que las personas querían assertNotEquals () era para comparar los elementos integrados sin tener que convertirlos primero en objetos completos:
Ejemplo detallado:
....
assertThat(1, not(equalTo(Integer.valueOf(winningBidderId))));
....
contra
assertNotEqual(1, winningBidderId);
Lamentablemente, ya que Eclipse no incluye JUnit 4.11 por defecto, debe ser detallado.
Advertencia: no creo que el ''1'' deba estar envuelto en un Integer.valueOf (), pero como acabo de regresar de .NET, no cuente con mi corrección.
Le sugiero que utilice las assertThat()
estilo assertThat()
más assertThat()
, que pueden describir fácilmente todo tipo de negaciones y generar automáticamente una descripción de lo que esperaba y lo que obtendría si la afirmación falla:
assertThat(objectUnderTest, is(not(someOtherObject)));
assertThat(objectUnderTest, not(someOtherObject));
assertThat(objectUnderTest, not(equalTo(someOtherObject)));
Las tres opciones son equivalentes, elija la que le resulte más legible.
Para usar los nombres simples de los métodos (y permitir que esta sintaxis tensa funcione), necesita estas importaciones:
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
Llego a esta fiesta bastante tarde pero he encontrado que la forma:
static void assertTrue(java.lang.String message, boolean condition)
Se puede hacer que funcione para la mayoría de los casos "no iguales".
int status = doSomething() ; // expected to return 123
assertTrue("doSomething() returned unexpected status", status != 123 ) ;
Me pregunto lo mismo. La API de Assert no es muy simétrica; para probar si los objetos son iguales, proporciona assertSame
y assertNotSame
.
Por supuesto, no es demasiado largo para escribir:
assertFalse(foo.equals(bar));
Con tal afirmación, la única parte informativa de la salida es desafortunadamente el nombre del método de prueba, por lo que el mensaje descriptivo debe formarse por separado:
String msg = "Expected <" + foo + "> to be unequal to <" + bar +">";
assertFalse(msg, foo.equals(bar));
Eso es, por supuesto, tan tedioso, que es mejor rodar tu propio assertNotEqual
. Por suerte en el futuro, tal vez forme parte de JUnit: JUnit número 22
Yo diría que la ausencia de assertNotEqual es de hecho una asimetría y hace que JUnit sea un poco menos aprendible. Tenga en cuenta que este es un buen caso cuando agregar un método disminuiría la complejidad de la API, al menos para mí: la simetría ayuda a controlar el espacio más grande. Mi conjetura es que la razón de la omisión puede ser que hay muy pocas personas que piden el método. Sin embargo, recuerdo un momento en el que incluso assertFalse no existía; por lo tanto, tengo una expectativa positiva de que el método podría agregarse eventualmente, dado que no es difícil; aunque reconozco que hay numerosas soluciones, incluso elegantes.