martes, 9 de enero de 2018

JUnit 5: Nuevas caracteristicas - 3

Ya hicimos varios post sobre JUnit 5 y en este veremos que nos ofrese su modelo de extensión.
Con la anotación '@ExtendWith' podremos registrar una o más extensiones de forma declarativa. Ya bien sean propias o de terceros. Además podremos indicarlo a nivel interfaz, clase o método. 

También se pueden registrar de forma automática de dos formas. O bién, indicando el nombre completo de la clase e incluyendo en un el fichero '/META-INF/services/org.junit.jupiter.api.extension.Extension'. O bién, habilitando la autodetección con la propiedad 'junit.jupiter.extensions.autodetection.enabled'. De esta forma las extensiones configuradas para ser detectadas por el 'ServiceLoader' serán cargadas correctamente.
A través de 'TestExecutionExceptionHandler' podemos crear clases que permitan el manejo de las excepciones. De esta forma, cuando se lance una excepción será capturada por nuestra clase y tratada según queramos. 


public class HandleExtension implements TestExecutionExceptionHandler {
 private final static Logger LOGGER = Logger.getLogger(HandleExtension.class);
 @Override
 public void handleTestExecutionException(final ExtensionContext context, final Throwable throwable)
   throws Throwable {
  LOGGER.info(throwable.getMessage(), throwable);
 }
}
.....
@Test
@ExtendWith(HandleExtension.class)
public void test() {
 int i = 1 / 0;
}
Con esta extensión podemos crear una clase que nos permita indicar condiciones dinamicas que nos permitan habilitar o deshabilitar los tests. Para ello debemos crear una clase que extienda de 'ExecutionCondition' y luego sea indicada en el método o clase a través de la anotación '@ExtendedWith'.

public class DayCondition implements ExecutionCondition {
 public ConditionEvaluationResult evaluateExecutionCondition(final ExtensionContext context) {
  Calendar cal = new GregorianCalendar();
  if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
   return ConditionEvaluationResult.disabled("Test disabled on Sundays");
  }
  return ConditionEvaluationResult.enabled("Test enabled today");
 }
}
.....
@Test
@ExtendWith(DayCondition.class)
public void test() {
 ...
}

Resolución de parámetros

A través de la implementación de 'ParameterResolver' podremos resolver en tiempo de ejecución cualquier parámetro que se pase a un constructor a a un método con la anotación  @Test, @TestFactory, @BeforeEach, @AfterEach, @BeforeAll, o @AfterAll que acepte un parámetro. Basicamente que hagamos una injección de dependencia.

public class BookDaoParameterResolver implements ParameterResolver {
    @Override
    public boolean supportsParameter(ParameterContext parameterContext, 
      ExtensionContext extensionContext) throws ParameterResolutionException {
        return parameterContext.getParameter().getType()
          .equals(BookDao.class);
    }
    @Override
    public Object resolveParameter(ParameterContext parameterContext, 
      ExtensionContext extensionContext) throws ParameterResolutionException {
        return new BookDao();
    }
}
...
@Test
@ExtendWith(HandleExtension.class)
public void test(BookDao dao) {
 Assert.assertThat(dao.get(1).getName(), equalTo('Tiger, tiger, tiger'));
}
Las extensiones se crean una única vez, pero tienen un mecanismo para permitir el paso de valores entre las distintas ejecuciones. Este mecanismo es el objeto 'Store' almacenado en el objeto 'ExtensionContext'. De esta forma podremos almacenar valores y recuperarlos entre las distintas ejecuciones. 

public class HandleExtension implements TestExecutionExceptionHandler {
 private final static Logger LOGGER = Logger.getLogger(HandleExtension.class);
 @Override
 public void handleTestExecutionException(final ExtensionContext context, final Throwable throwable)
   throws Throwable {
  Integer time = (Integer) getStore(context).get("time");
  time++;
  LOGGER.info("Exception throw for " + time + " time");
  getStore(context).put("time", time);
 }
 private Store getStore(final ExtensionContext context) {
  return context.getStore(Namespace.create(getClass(), context));
 }
}

No hay comentarios:

Publicar un comentario