Junit4: Presenta la jerarquía de BiMatcher

Creado en 8 feb. 2018  ·  9Comentarios  ·  Fuente: junit-team/junit4

Una buena característica sería introducir la jerarquía BiMatcher (análoga a org.hamcrest.Matcher , pero consumiendo 2 argumentos). Alternativamente, el estándar Comparator se puede utilizar para este propósito. También se puede usar BiPredicate (esto vinculará JUnit a Java-8, pero agregará lógica Y / O / NO lista para usar).
Un par de notas para todo el código adicional:

  • BiMatcher nombres BiPredicate y Comparator se usarán indistintamente.
  • Todo el código no es final y solo una idea general.

Métodos principales para agregar Assert class:

  • assertThat(T expected, T actual, Comparator<T> biMatcher);
  • assertThat(String message, T expected, T actual, Comparator<T> biMatcher); (tal vez no sea necesario, ver más abajo).
  • Múltiples métodos assertArray() (ver más abajo).

La motivación: a veces es necesario realizar muchas comprobaciones similares en lotes de objetos. La funcionalidad existente lo permite, pero con mucho código adicional (bucles y condiciones). Con Comparator se puede hacer con menos código y con mayor flexibilidad.

Ejemplo real (a partir del cual comencé a pensar en esta característica): es necesario probar que todos los objetos en la matriz son iguales o no iguales (dependiendo de una bandera booleana).

Con las habilidades actuales de JUnit, se verá así:
más corta:

for (int i = 0; i < elements.length - 1; i++) {
  if (checkSame) { // Same
    assertSame("elements must be the same.", elements[i], elements[i + 1]);
  } else { // Not same
    assertNotSame("elements must be not the same.", elements[i], elements[i + 1]);
  }
}

mejor rendimiento (pero a quién le importa el rendimiento en las pruebas):

if (checkSame) { // Same
  for (int i = 0; i < elements.length - 1; i++) {
    assertSame("elements must be the same.", elements[i], elements[i + 1]);
  }
else { // Not same
  for (int i = 0; i < elements.length - 1; i++) {
    assertNotSame("elements must be not the same.", elements[i], elements[i + 1]);
  }
}

También podemos implementar el propio Comparator y usar assertTrue()/assertFalse() , pero el código para crear comparadores también será grande (a menos que usemos lambdas).

Con el nuevo código de enfoque se verá mucho más corto y más limpio que para mí, así:

Comparator<T> comparator = checkSame ? BiMatchers.same() : BiMatchers.notSame();
String message = checkSame ? "elements must be the same." : "elements must be not the same.";
for (int i = 0; i < elements.length - 1; i++) {
  assertThat(message, elements[i], elements[i + 1], comparator);
}

Para hacerlo aún más corto, podemos extender Comparator a MessagedComparator con la propiedad opcional message , por lo que JUnit lo tomará de allí de alguna manera. Como esto:

MessagedComparator<T> comparator = checkSame ? BiMatchers.same("elements must be the same.") : BiMatchers.notSame("elements must be not the same.");
for (int i = 0; i < elements.length - 1; i++) {
  assertThat(message, elements[i], elements[i + 1], comparator);
}

Las consecuencias son de gran alcance:
1) La clase Assert será muy flexible en general, porque puedes usar cualquier comparador estándar o propio sin mucho código.
2) Como resultado de lo anterior, las lambdas se pueden usar más fácilmente para inyectar cualquier condición.
3) Se puede agregar una cascada lógica adicional (Y, O, NO) lista para usar (algo similar a org.hamcrest.CoreMatchers ). Actualmente, para cualquier mini función nueva se requiere un nuevo método, por ejemplo, assertNotSame() junto a assertSame() etc. O nuevamente necesitamos los métodos assertTrue()/assertFalse() .
4) Toda la clase Assert se puede refactorizar a la forma unificada. Solo un ejemplo:

public static void assertSame(String message, Object expected, Object actual) {
  assertThat(message, expected, actual, BiMatchers.same())
}

public static void assertThat(String message, T expected, T actual, Comparator<T> biMatcher) {
...
}

o como ya se mencionó:

public static void assertSame(String message, Object expected, Object actual) {
  assertThat(expected, actual, BiMatchers.same(message))
}

public static void assertThat(T expected, T actual, MessagedComparator<T> biMatcher) {
...
}

5) Se pueden agregar métodos assertArray() (por lo tanto, los métodos antiguos se pueden refactorizar). P.ej:

public static void assertArrayEquals(boolean[] expecteds, boolean[] actuals) {
  assertArray(expecteds, actuals, BiMatchers.equals());
}

public static void assertArray(boolean[] expecteds, boolean[] actuals, Comparator<Boolean>) {
...
}

Entonces, por ejemplo, puede verificar que todos los elementos en 2 matrices sean tan fáciles como:

Assert.assertArray(array1, array2, BiMatchers.same());

Además, las comprobaciones de longitud de matriz u otras se pueden controlar por separado. Pseudocódigo:

Assert.assertArray(array1, array2, and(sameLength(), same()));

Todos 9 comentarios

Gracias por sacar este tema.

Preferiría que JUnit 4.x no agregue más DSL de aserción. Es realmente difícil conseguir un DSL correcto y flexible, y no estoy seguro de que tenga sentido dedicar tiempo y esfuerzo a eso en JUnit cuando hay buenos marcos de afirmación de terceros como Truth o Fest.

Además, las funciones que requieren Java 8 deben ir a http://github.com/junit-team/junit5

@gitIvanB Gracias por abrir el problema. Al igual que @kcooney , también creo que esto se abordaría mejor con una biblioteca de aserciones, por ejemplo, AssertJ.

@kcooney , @marcphilipp , gracias por insinuar. Parece que el uso de librerías de aserción es una buena práctica aquí.
Una pregunta adicional. ¿Puedo usar como regla general que el uso de Assert está desaprobado (o no se recomienda)? Especialmente teniendo en cuenta la posible actualización futura de JUnit-4 a JUnit-5.

@gitIvanB La pregunta no está un poco clara. Si se desarrolla contra junit4 se usa org.junit.Assert , si se desarrolla contra junit5 entonces org.junit.jupiter.api.Assertions

El enfoque recomendado es importar métodos estáticamente desde él, para evitar tener Assert. en cada línea.

@gitIvanB Definitivamente no deberías usar junit.framework.Assert , pero org.junit.Assert está bien. Cuando actualice, puede usar un IDE para convertir JUnit 4 a aserciones de JUnit Jupiter (IDEA ya lo admite). La mayor diferencia es que el parámetro de mensaje opcional aparece primero en JUnit 4 pero último en Júpiter. Alternativamente, puede decidir usar una biblioteca de aserciones diferente ahora y seguir usándola al migrar de Vintage a Jupiter.

@panchenko , @marcphilipp Entonces, según entendí, el org.junit.Assert JUnit-4 está sellado y no se enriquecerá con nuevos métodos. En JUnit-5 necesito usar org.junit.jupiter.api.Assertions (como reemplazo de org.junit.Assert ) o algún lib de aserción.
Necesito algo de tiempo para aprender JUnit-5, pero desde el primer vistazo a org.junit.jupiter.api.Assertions parece que su enfoque en general es similar a org.junit.Assert . Por lo tanto, es muy probable que necesite crear un ticket similar para JUnit-5 :) Creo que JUnit-5 debería proporcionar aserciones completas o delegar completamente a las bibliotecas de aserción.

@gitIvanB La filosofía de JUnit es proporcionar un marco bueno y extensible para escribir pruebas para Java en Java. Al ser un marco extensible, a menudo vemos que otros proyectos de código abierto extienden el marco y / o proporcionan bibliotecas de prueba enriquecidas que se pueden usar con JUnit.

Para las aserciones, hay varios proyectos que proporcionan un conjunto más rico de aserciones, a veces de forma extensible.
Por ejemplo, existe Google Truth (https://github.com/google/truth), FEST (https://github.com/alexruiz/fest-assert-2.x), AssertJ (http: // joel- costigliola.github.io/assertj/) y Hamcrest (http://hamcrest.org/JavaHamcrest/).

Debido a que hay tantas bibliotecas de afirmaciones increíbles por ahí, me he mostrado reacio a aceptar solicitudes de nuevas funciones por org.junit.Assert . No lo consideraría congelado (aunque consideraría junit.framework.Assert congelado). De hecho, 4.13 introducirá assertThrows . Pero dado que nunca tendremos un conjunto de afirmaciones tan rico como esos proyectos, nos sentimos cómodos proporcionando lo básico.

Dicho de otra manera, se han formado comunidades saludables en torno al uso y mantenimiento de esos proyectos, así que creo que deberíamos aceptarlos y apoyarlos.

No puedo hablar por JUnit5, pero imagino que los desarrolladores originales sintieron que no podían lanzar la próxima generación de JUnit sin una buena base de métodos de afirmación (o tal vez sintieron que era la mejor manera de asegurarse de que el nuevo marco fuera funcional y pulido fue probar JUnit5 usando JUnit5). Las nuevas prácticas de programación hicieron que tomaran decisiones diferentes sobre cómo se vería una API de aserción básica que Kent, Erich y David, por lo que verá algunas diferencias. Pero probablemente nunca verá en JUnit un conjunto de afirmaciones tan rico como con Hamcrest o un DSL extensible como Truth.

Dejo que el equipo de JUnit5 decida qué tipo de cambios considerarán. Si sientes firmemente que el
Los métodos que proponga son importantes como base para escribir buenas pruebas. Siéntase libre de crear un problema allí.

Cuando comenzamos a trabajar en JUnit 5 (nombre en código "JUnit Lambda" en ese momento), discutimos el alcance de lo que queríamos lograr. Se decidió explícitamente que escribir un nuevo tipo de biblioteca de afirmaciones no estaría dentro del alcance.

O, como dice la Guía del usuario de JUnit 5 :

Aunque las facilidades de afirmación proporcionadas por JUnit Jupiter son suficientes para muchos escenarios de prueba, hay momentos en los que se desea o se requiere más potencia y funcionalidad adicional, como los comparadores. En tales casos, el equipo de JUnit recomienda el uso de bibliotecas de aserciones de terceros como AssertJ, Hamcrest, Truth, etc. Por lo tanto, los desarrolladores son libres de utilizar la biblioteca de aserciones de su elección.

Por lo tanto, tampoco está congelado, pero el objetivo es similar al de JUnit 4, es decir, proporcionar un conjunto básico de afirmaciones para que los usuarios comiencen. Incluso usamos AssertJ para nuestras propias pruebas unitarias.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

diogoeag picture diogoeag  ·  35Comentarios

lvc picture lvc  ·  6Comentarios

forvoid picture forvoid  ·  8Comentarios

gonzen picture gonzen  ·  7Comentarios

sbrannen picture sbrannen  ·  22Comentarios