2011-07-16 16 views
26

Tengo una serie de casos de prueba en JUnit. Todos ellos necesitan el mismo código para ejecutarse en su método estático @BeforeClass. Es una duplicación de código y estoy tratando de deshacerme de ella. Una manera sucia de hacer esto es por herencia. ¿Hay algún otro mecanismo en JUnit que pueda ayudar?Cómo evitar la herencia en los casos de prueba JUnit?

PS. Escribí esta publicación en el blog sobre este mismo tema: http://www.yegor256.com/2015/05/25/unit-test-scaffolding.html

+0

¿Son todas las '@ BeforeClasses' exactamente iguales o simplemente comparten algún código? –

+1

¿Por qué la herencia es una manera sucia? –

+0

@lu, el método es estático y la herencia no sería lo mejor. –

Respuesta

26

La forma JUnit para componer código reutilizable (en lugar de heredar de él) son Reglas.

Ver https://github.com/junit-team/junit/wiki/Rules

Este es un ejemplo tonto, pero obtendrá el punto.

import org.junit.rules.TestRule; 
import org.junit.runners.model.Statement; 
import org.junit.runner.Description; 

public class MyTestRule implements TestRule { 
    @Override 
    public Statement apply(final Statement statement, Description description) { 
    return new Statement() { 
     public void evaluate() throws Throwable { 
     // Here is BEFORE_CODE 
     try { 
      statement.evaluate(); 
     } finally { 
      // Here is AFTER_CODE 
     } 
     } 
    }; 
    } 
} 

entonces usted puede utilizar su TestRule así:

import org.junit.Rule; 

public class MyTest { 
    @Rule 
    public MyTestRule myRule = new MyTestRule(); 
} 

BEFORE_CODE y AFTER_CODE A continuación, se ejecuta alrededor de cada uno de sus métodos de prueba.

Si usted necesita para ejecutar su código sólo una vez por cada clase, utilice su TestRule como @ClassRule:

import org.junit.ClassRule; 

public class MyTest { 
    @ClassRule 
    public static MyTestRule myRule = new MyTestRule(); 
} 

Ahora, BEFORE_CODE y AFTER_CODE se ejecutará alrededor de cada uno de su clase de prueba.

@Rule campo no es estático, @ClassRule campo es.

Una @ClassRule también se puede declarar en una suite.

Tenga en cuenta que puede declarar varias reglas en una única clase de prueba, así es como se componen los ciclos de vida de prueba en niveles de prueba-suites, clases de prueba y métodos de prueba.

Una regla es un objeto que usted instancia en sus clases de prueba (estáticamente o no). Puede agregar parámetros contructor si es necesario.

HTH

4

Si el método es algún tipo de utilidad, sepárela a una clase diferente con un método estático y llame a ese método en su @BeforeClass.

Subrayo el hecho de que no utilices la herencia solo porque resuelve tu problema, úsala cuando creas sentido en la jerarquía de tu clase.

0

Si todos y cada clase tiene que tener un método anotado @BeforeClass que es exactamente lo mismo que todos los demás, entonces la herencia no se siente que mal a mí. Si cada uno de estos métodos de inicialización simplemente comparte algún código, puede crear una clase TestUtil con cierto comportamiento compartido y realizar llamadas a este comportamiento compartido desde cada uno de los métodos @BeforeClass.

1

Los métodos estáticos no se heredan, por lo que la herencia no es una opción por defecto. Si te refieres a que estás moviendo el método a una clase principal común, entonces parece una opción pobre ya que solo obtienes un padre en Java. Una clase de soporte de prueba de algún tipo parece más apropiada. También es posible que vea la necesidad de un parameterized test.

0

Creo que si las clases tienen "is-a" relación, la herencia es razonable.

Si la clase base es MyBeforeClass que define @BeforeClass método, y MyTestClass1 "es-a" MyBeforeClass, MyTestClass1 extends MyBeforeClass es OK.

0

Dependiendo de la naturaleza del código de configuración, puede potencialmente poner todas sus pruebas en una prueba suite y hacer que el código de configuración se ejecute allí. La desventaja de esto es que no puede ejecutar las pruebas de forma individual (ya que la prueba depende del código de configuración).

1

No hay absolutamente nada de malo en la herencia en este caso, en realidad es la única forma de evitar repetir este código en cada subclase. El hecho de que los métodos @BeforeClass tengan que declararse estáticos en JUnit es desafortunado, pero eso no debería detenerlo. Extienda la clase y el código de inicialización se ejecutará automáticamente sin tener que hacer nada.

+0

No, no es la única manera, ver otras respuestas, y como los métodos estáticos no son heredados, es dudoso que sea de alguna manera. ¿Lo has probado? – EJP

2

Es posible crear corredor de prueba

public class MyTestRunner extends BlockJUnit4ClassRunner { 
    @Override 
    protected Object createTest() throws Exception { 
    Object test = super.createTest(); 
    doStuff(); 
    } 

    public void doStuff(){ 
    //common code 
    } 
} 


@RunWith(MyTestRunner.class) 
public class MyTest1{ 
    @Test 
    public void test1(){ 
     //test method 
    } 
} 
-2

Es código de prueba, y no está destinado para su reutilización pesada. No sobreinnovar. No aplique todos los patrones de diseño que conoce. Para código de prueba, las reglas son diferentes.

Cuestiones relacionadas