¿Puede agregar un mensaje personalizado a AssertJ assertThat?

90

Tenemos un conjunto de pruebas que usa principalmente aserciones JUnit con comparadores Hamcrest. Uno de nuestro equipo comenzó a experimentar con AssertJ e impresionó a la gente con su sintaxis, flexibilidad y declaratividad. Hay una característica que proporciona JUnit para la que no puedo encontrar un equivalente en AssertJ: agregar un mensaje de falla de aserción personalizado.

A menudo comparamos objetos que no están hechos para ser legibles por humanos y que tendrán ID o UUID de apariencia aleatoria y es imposible saber qué se supone que son por los datos que contienen. Esta es una situación ineludible para nuestro código base, lamentablemente, ya que parte del propósito que cumple es mapear datos entre otros servicios sin necesariamente comprender de qué se trata.

En JUnit, el assertThatmétodo proporciona una versión con un String reasonparámetro antes de Matcher<T>param. Esto hace que sea trivial agregar una cadena de depuración corta que arroje algo de luz sobre el problema, como lo que debería significar la comparación para un humano.

AssertJ, por el contrario, proporciona un jillion diferentes genericizedstatic assertThat métodos que devuelven algún tipo de interfaz de aserción o una de sus muchas clases de ejecución. Esta interfaz no proporciona una forma estándar de configurar un mensaje personalizado para que se incluya con fallas.

¿Hay alguna forma de obtener esta funcionalidad de la API de AssertJ o una de sus extensiones sin tener que crear una clase de aserción personalizada para cada tipo de aserción al que queramos agregar mensajes?

Patrick M
fuente

Respuestas:

137

Y de manera clásica, encontré lo que estaba buscando momentos después de publicar la pregunta. Con suerte, esto hará que sea más fácil para la próxima persona encontrarlo sin tener que saber primero cómo se llama. El método mágico es engañosamente abreviado as, que es parte de otra interfaz que AbstractAssertimplementa: Descriptable , no la interfaz Assert base.

public S as(String description, Object... args)

Establece la descripción de la String.format(String, Object...)sintaxis de soporte de este objeto .
Ejemplo:

try {
  // set a bad age to Mr Frodo which is really 33 years old.
  frodo.setAge(50);
  // you can specify a test description with as() method or describedAs(), it supports String format args
  assertThat(frodo.getAge()).as("check %s's age", frodo.getName()).isEqualTo(33);
} catch (AssertionError e) {
  assertThat(e).hasMessage("[check Frodo's age] expected:<[33]> but was:<[50]>");
}

Donde esa cadena entre comillas en el bloque catch hasMessagees lo que aparece en el registro de salida de la prueba unitaria si falla la afirmación.


Encontré esto al notar el failWithMessageayudante en la página de aserción personalizada vinculada en la pregunta. El JavaDoc para ese método señala que está protegido, por lo que las personas que llaman no pueden usarlo para establecer un mensaje personalizado. Sin embargo, menciona al asayudante:

Además, este método respeta cualquier descripción establecida as(String, Object...)o un mensaje de error anulado definido por el usuario con overridingErrorMessage(String, Object...).

... y el overridingErrorMessage ayudante, que reemplaza totalmente la norma AssertJ expected: ... but was:...mensaje con la nueva cadena proporcionada.

La página de inicio de AssertJ no menciona ningún ayudante hasta que la página de características destacadas, que muestra ejemplos del asayudante en la sección Soft Assertions , pero no describe directamente lo que hace.

Patrick M
fuente
22

Para agregar otra opción a la respuesta de Patrick M:

En lugar de usar Descriptable.as, también puede usar AbstractAssert.withFailMessage():

try {
  // set a bad age to Mr Frodo which is really 33 years old.
  frodo.setAge(50);
  // you can specify a test description via withFailMessage(), supports String format args
  assertThat(frodo.getAge()).
    withFailMessage("Frodo's age is wrong: %s years, difference %s years",
      frodo.getAge(), frodo.getAge()-33).
    isEqualTo(33);
} catch (AssertionError e) {
  assertThat(e).hasMessage("Frodo's age is wrong: 50 years, difference 17 years");
}

La diferencia con el uso Descriptable.ases que le da un control completo sobre el mensaje personalizado - no hay "esperado" ni "pero fue".

Esto es útil cuando los valores reales que se están probando no son útiles para la presentación; este método le permite mostrar otros valores posiblemente calculados en su lugar, o ninguno en absoluto.


Tenga en cuenta que, al igual que Descriptable.as, debe llamar withFailMessage() antes de cualquier aserción real; de lo contrario, no funcionará, ya que la aserción se activará primero. Esto se indica en el Javadoc.

sleske
fuente
3
"debe llamar conFailMessage () antes de cualquier afirmación real" gracias, esto me hizo tropezar. El orden de la llamada withFailMessageimporta; Me gusta AssertJ, pero esto apesta.
Abhijit Sarkar
0

Utilice el as()método incorporado en AssertJ. Por ejemplo:

 assertThat(myTest).as("The test microservice is not active").isEqualTo("active");
Testilla
fuente