Cómo evitar la herencia en los casos de prueba JUnit?


Tengo una serie de casos de prueba en JUnit. Todos ellos necesitan el mismo código para ser ejecutados en su método estático @BeforeClass. Es una duplicación de código y estoy tratando de deshacerme de él. Una manera sucia de hacer esto es por herencia. ¿Hay otros mecanismos en JUnit que puedan ayudar?

PS. Escribí esta entrada de blog sobre este mismo tema: http://www.yegor256.com/2015/05/25/unit-test-scaffolding.html

 34
Author: yegor256, 2011-07-16

9 answers

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

Véase https://github.com/junit-team/junit/wiki/Rules

Aquí hay una muestra tonta, pero entenderás 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 puedes usar tu TestRule así:

import org.junit.Rule;

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

BEFORE_CODE y AFTER_CODE se ejecutarán alrededor de cada uno de sus métodos de prueba.

Si necesita ejecutar su código solo una vez por clase, use 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án alrededor de cada una de sus clases de prueba.

@El campo Rule no es estático, el campo @ClassRule sí.

También se puede declarar un @ClassRule en una suite.

Tenga en cuenta que puede declarar varias reglas en una sola clase de prueba, así es como compone los ciclos de vida de prueba en los niveles de conjuntos de pruebas, clases de prueba y métodos de prueba.

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

HTH

 33
Author: eskatos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-18 14:44:32

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

Hago hincapié en el hecho de que no use la herencia solo porque resuelve su problema, úselo cuando lo haga crea sentido en su jerarquía de clases.

 4
Author: Suraj Chandran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-16 08:32:07

Puede crear test runner

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
Author: Marcin Michalski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-23 06:05:06

Los métodos estáticos no se heredan, por lo que la herencia no es una opción predeterminada. Si quieres decir que estás moviendo el método a una clase padre común, entonces eso parece una mala elección ya que solo obtienes un padre en Java. Una clase de apoyo de prueba de algún tipo parecería más apropiado. También es posible que esté viendo la necesidad de una prueba parametrizada .

 1
Author: Ryan Stewart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-16 04:39:38

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

 1
Author: Cedric Beust,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-16 21:18:36

Si todas y cada una de las clases necesitan tener un @BeforeClass método anotado que es exactamente el mismo que cualquier otra, entonces la herencia no me parece que está mal. Si cada uno de estos métodos de inicialización simplemente comparte algún código, podría crear una clase TestUtil con algún comportamiento compartido y hacer llamadas a este comportamiento compartido desde cada uno de los métodos @BeforeClass.

 0
Author: Ray Toal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-16 04:26:12

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

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

 0
Author: 卢声远 Shengyuan Lu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-16 04:41:56

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

 0
Author: James Kingsbery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-16 04:48:01

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

 -2
Author: Michael Piefel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-26 06:36:15