Matchers personalizados con Hamcrest
⏱ Dedicación recomendada: 0 minutos
Esto considera el contenido visible y relevante, e ignora texto colapsado o marcado como opcional.
r8vnhill/
Hamcrest es una librería de matchers para Java que se utiliza comúnmente con JUnit para escribir aserciones más legibles y expresivas.
Estructura de un Matcher en Hamcrest
Para crear un matcher personalizado en Hamcrest, debes extender la clase TypeSafeMatcher<T>
, donde T
es el tipo de objeto que estás probando. Debes implementar dos métodos clave:
matchesSafely(T item)
: Contiene la lógica de la comparación.describeTo(Description description)
: Proporciona una descripción del matcher para los mensajes de error.
Crear un Matcher para Verificar Números Pares
Vamos a crear un matcher personalizado que verifique si un número entero es par, similar al ejemplo de Kotest.
- Código esencial
- Código completo
public class IsEvenMatcher extends TypeSafeMatcher<Integer> {
@Override
protected boolean matchesSafely(Integer number) {
return number % 2 == 0;
}
@Override
public void describeTo(Description description) {
description.appendText("an even number");
}
@Override
protected void describeMismatchSafely(Integer number, Description mismatchDescription) {
mismatchDescription.appendText("was ").appendValue(number);
}
public static IsEvenMatcher isEven() {
return new IsEvenMatcher();
}
}
package cl.ravenhill.hamcrest.even;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
public class IsEvenMatcher extends TypeSafeMatcher<Integer> {
@Override
protected boolean matchesSafely(Integer number) {
return number % 2 == 0;
}
@Override
public void describeTo(@NotNull Description description) {
description.appendText("an even number");
}
@Override
protected void describeMismatchSafely(Integer number, @NotNull Description mismatchDescription) {
mismatchDescription.appendText("was ").appendValue(number);
}
@NotNull
@Contract(" -> new")
public static IsEvenMatcher isEven() {
return new IsEvenMatcher();
}
}
Usar el Matcher Personalizado en Pruebas
Ahora, podemos utilizar el matcher isEven()
en nuestras pruebas con JUnit:
- Código esencial
- Código completo
assertThat(2, isEven());
assertThat(3, not(isEven()));
package cl.ravenhill.hamcrest.even;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static cl.ravenhill.hamcrest.even.IsEvenMatcher.isEven;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class IsEvenTest {
@DisplayName("Given an even number, when checking if it is even, then it should pass")
@Test
void testEvenNumberIsEven() {
assertThat(2, isEven());
}
@DisplayName("Given an even number, when checking if it is not even, then it should fail")
@Test
void testEvenNumberIsNotEven() {
assertThrows(AssertionError.class, () -> assertThat(2, not(isEven())));
}
@DisplayName("Given an odd number, when checking if it is not even, then it should pass")
@Test
void testOddNumberIsNotEven() {
assertThat(3, not(isEven()));
}
@DisplayName("Given an odd number, when checking if it is even, then it should fail")
@Test
void testOddNumberIsEven() {
assertThrows(AssertionError.class, () -> assertThat(3, isEven()));
}
}
Comparación Final
Característica | Kotest | Hamcrest |
---|---|---|
Sintaxis | Uso de lambdas y funciones in-line para definir matchers personalizados de manera concisa. | Necesita definir clases completas para crear un matcher, lo que añade verbosidad. |
Reutilización | Fácil reutilización con la función Matcher que acepta lambdas. | Se crean clases reutilizables pero requieren más código para definirlas. |
Composición de Matchers | Fácil de componer múltiples matchers usando should y shouldNot . | Utiliza assertThat y combinaciones con Matchers como not o allOf . |
Mensajes de Error | Define mensajes de error y mensajes negados de forma sencilla con lambdas. | Debes implementar los métodos describeTo y describeMismatchSafely . |
Compatibilidad con Frameworks | Nativo para proyectos de Kotlin, integración fluida con Kotest. | Ampliamente utilizado en Java, compatible con frameworks como JUnit. |
Beneficios y limitaciones
Beneficios
- Madurez y Adopción: Es una biblioteca madura con una gran base de usuarios y soporte en muchos proyectos Java, incluido JUnit.
- Versatilidad: Hamcrest ofrece una amplia variedad de matchers prediseñados, y su enfoque basado en clases permite definir comportamientos muy personalizados y detallados.
- Composición poderosa: Hamcrest permite componer matchers de manera muy expresiva, como combinar condiciones con
allOf
,anyOf
, y otros.
Limitaciones
- Verboso: La creación de un matcher personalizado requiere definir una clase completa y múltiples métodos, lo que puede ser innecesariamente detallado para casos simples.
- Sintaxis antigua: Comparado con Kotest, que utiliza funciones in-line y lambdas, la sintaxis de Hamcrest puede parecer más arcaica y menos intuitiva para nuevxs desarrolladorxs.
¿Qué aprendimos?
En esta lección, hemos explorado cómo crear matchers personalizados en Hamcrest y compararlos con la experiencia en Kotest.
Puntos clave
- Estructura de los Matchers: En Hamcrest, crear un matcher personalizado implica extender la clase
TypeSafeMatcher
y sobrescribir métodos comomatchesSafely
,describeTo
, ydescribeMismatchSafely
. Esta estructura es más detallada y verbosa en comparación con Kotest. - Reutilización y Flexibilidad: Mientras que en Kotest puedes definir matchers personalizados de forma concisa usando lambdas, en Hamcrest necesitas crear una clase completa, lo que añade un poco de complejidad, pero también ofrece más control y personalización en la lógica del matcher.
- Compatibilidad y Adopción: Hamcrest es muy utilizado en proyectos Java, especialmente en combinación con JUnit, lo que lo hace ideal para entornos Java maduros. Kotest, en cambio, está más orientado a proyectos en Kotlin, ofreciendo una sintaxis más moderna y flexible.
Hamcrest sigue siendo una excelente opción en el ecosistema Java, especialmente para proyectos que requieren un control detallado y personalizado en las aserciones. Sin embargo, para aquellos que prefieren una sintaxis más concisa y moderna, especialmente en Kotlin, Kotest puede ser una alternativa más atractiva.
Ambas librerías tienen sus propias ventajas, por lo que la elección entre Hamcrest y Kotest dependerá del lenguaje y las necesidades específicas de tu proyecto.
Bibliografías Recomendadas
- 🌐 "Hamcrest Tutorial." Accedido: 4 de octubre de 2024. [En línea]. Disponible en: https://hamcrest.org/JavaHamcrest/tutorial