JUnit 4.7: @Rule

En mi empresa nos estamos tomando bastante enserio el tema de los tests, así que he dedicado algunos ratos libres a buscar herramientas que nos ayuden en esta tarea. Entre otras cosas, he leído sobre la versión 4.7 de JUnit, y descubrí una característica bastante interesante. Para presentarla, voy a seguir un ejemplo que probablemente haga que se les ponga los pelos de punta a muchos, pero creo que es un ejemplo bastante sencillo y claro.

Supongamos que tenemos una batería de test, y de alguna forma queremos hacer que ciertos tests se ejecuten los días pares y el resto los impares. Lo primero es definir una nueva anotación para poder anotar en los test si se deben ejecutar los días pares o los impares.

package es.gmr.junit;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DateAnnotation {
  boolean ejecutarDiasPares() default true;
}


Esta nueva funcionalidad de JUnit, requiere que creemos una clase que implemente la interfaz MethodRule. Esta clase interceptará las llamadas a los métodos del test y realizará las acciones convenientes, que en nuestro caso es ejecutar el método si se cumple la condición adecuada (día par o impar).

package es.gmr.junit;

import java.util.Calendar;

import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;

public class ManejadorEjecucion implements MethodRule {
  @Override
  public Statement apply(Statement stament, final FrameworkMethod frameworkMethod, final Object obj) {
    return new Statement() {
        @Override
public void evaluate() throws Throwable {
DateAnnotation dateAnnotation = frameworkMethod.getAnnotation(DateAnnotation.class);
if (dateAnnotation == null) {
frameworkMethod.invokeExplosively(obj);
else {
Calendar calendar = Calendar.getInstance();
boolean hoyEsPar = calendar.get(Calendar.DAY_OF_MONTH== 0;
boolean ejecutarDiasPares = dateAnnotation.ejecutarDiasPares();

if hoyEsPar && ejecutarDiasPares || !hoyEsPar && !ejecutarDiasPares){
frameworkMethod.invokeExplosively(obj);
}
}
            }
        };
}
}



Por último, en la clase donde se implementan los test, debe haber declarada una variable pública del tipo de la clase que hemos implementado en el punto anterior (ManejadorEjecucion) y anotada con @Rule.

package es.gmr.junit;

import org.junit.Rule;
import org.junit.Test;

public class TestPruebas {

  @Rule
  public ManejadorEjecucion manejadorEjecucion = 
    new ManejadorEjecucion();

  @Test
  @DateAnnotation(ejecutarDiasPares = true)
  public void diasParesTest(){
    System.out.println("Hoy es par");
    // ...
  }

  @Test
  @DateAnnotation(ejecutarDiasPares = false)
  public void diasImparesTest(){
    System.out.println("Hoy es impar");
    //...
  }
}



Al ejecutar, veremos que hoy sólo se lanzará el test diasImparesTest.

Como comentaba al principio, esto es sólo un ejemplo para "jugar" con esta anotación. He estado haciendo pruebas para crear mocks, o probar concurrencia, pero son ejemplos que seguro que se llevarían muchas más líneas.

Comentarios