2010-04-28 3 views
30

Uso servidores integrados que se ejecutan dentro de casos de prueba de Junit. A veces estos servidores requieren un directorio de trabajo (por ejemplo, el servidor Apache Directory).Cómo gestionar el pedido de @ Rule cuando son dependientes entre sí

La nueva @Rule en Junit 4.7 puede manejar estos casos. TemporaryFolder-Rule puede crear un directorio temporal. Se puede crear una regla de recurso externo personalizada para el servidor. Pero ¿Cómo manejo si quiero pasar el resultado de una regla a la otra;

import static org.junit.Assert.assertEquals; 
import java.io.*; 
import org.junit.*; 
import org.junit.rules.*; 

public class FolderRuleOrderingTest { 

    @Rule 
    public TemporaryFolder folder = new TemporaryFolder(); 

    @Rule 
    public MyNumberServer server = new MyNumberServer(folder); 

    @Test 
    public void testMyNumberServer() throws IOException { 
     server.storeNumber(10); 
     assertEquals(10, server.getNumber()); 
    } 

    /** Simple server that can store one number */ 
    private static class MyNumberServer extends ExternalResource { 

     private TemporaryFolder folder; 

     /** The actual datafile where the number are stored */ 
     private File dataFile; 

     public MyNumberServer(TemporaryFolder folder) { 
      this.folder = folder; 
     } 

     @Override 
     protected void before() throws Throwable { 
      if (folder.getRoot() == null) { 
       throw new RuntimeException("TemporaryFolder not properly initialized"); 
      } 

      //All server data are stored to a working folder 
      File workingFolder = folder.newFolder("my-work-folder"); 
      dataFile = new File(workingFolder, "datafile"); 
     } 

     public void storeNumber(int number) throws IOException { 
      dataFile.createNewFile(); 
      DataOutputStream out = new DataOutputStream(new FileOutputStream(dataFile)); 
      out.writeInt(number); 
     } 

     public int getNumber() throws IOException { 
      DataInputStream in = new DataInputStream(new FileInputStream(dataFile)); 
      return in.readInt(); 
     } 
    } 
} 

En este código de la carpeta se envía como un parámetro en el servidor para que el servidor puede crear un directorio de trabajo para almacenar datos . Sin embargo, esto no funciona porque Junit procesa las reglas en orden inverso ya que están definidas en el archivo. La Regla TemporaryFolder no se ejecutará antes de la Regla del servidor. Por lo tanto, la carpeta raíz en TempraryFolder será nula, lo que resulta en que los archivos se crean en relación con el directorio de trabajo actual.

Si invierto el orden de los atributos en mi clase, obtengo un error de compilación porque no puedo hacer referencia a una variable antes de que esté definida.

estoy usando Junit 4.8.1 (ya que el orden de las reglas se fijó un poco de la versión 4.7)

+0

¿Cómo se solucionó el problema de 4.7 a 4.8? – zedoo

Respuesta

3

Si no se encuentra solución normal, siempre se puede crear regla compuesto (y el único teniendo la anotación @Rule) que contiene todos los demás y los ejecuta en orden.

+0

Sí, eso funcionará. Tiene la desventaja de que la carpeta no se puede compartir fácilmente entre otros códigos en el caso de prueba. –

35

EDITAR: Con el Junit 4.10 recientemente publicado, puede usar @RuleChain para encadenar las reglas correctamente (ver al final).

Usted podría introducir otro campo privado, sin la anotación @Rule, a continuación, puede cambiar el orden de su código como desee:

public class FolderRuleOrderingTest { 

    private TemporaryFolder privateFolder = new TemporaryFolder(); 

    @Rule 
    public MyNumberServer server = new MyNumberServer(privateFolder); 

    @Rule 
    public TemporaryFolder folder = privateFolder; 

    @Test 
    public void testMyNumberServer() throws IOException { 
     server.storeNumber(10); 
     assertEquals(10, server.getNumber()); 
    } 
    ... 
} 

La solución más limpia es tener una regla compuesto, pero lo anterior debería funcionar.

EDIT: Con el recientemente lanzado Junit 4.10, puede utilizar RuleChain la normativa cadena correctamente:

public static class UseRuleChain { 
    @Rule 
    public TestRule chain= RuleChain 
          .outerRule(new LoggingRule("outer rule")) 
          .around(new LoggingRule("middle rule")) 
          .around(new LoggingRule("inner rule")); 

    @Test 
    public void example() { 
      assertTrue(true); 
    } 
} 

escribe el registro

starting outer rule 
starting middle rule 
starting inner rule 
finished inner rule 
finished middle rule 
finished outer rule 
+0

¿Y si quiero acceder a la regla desde dentro de una prueba? ¿Alguna forma de acceder al contenido del campo 'chain'? – Henrik

+2

No hay nada que le impida declarar una regla como campo privado en su clase y luego usarla en RuleChain. A continuación, tendrías acceso a ella en la Prueba –

+1

Ah, por supuesto. Tan simple que me lo perdí en mi búsqueda frenética de acceso de clase. Gracias. – Henrik

5

Para hacer las reglas dependientes, su tiene inicializarlas primero y crea las relaciones de dependencia usando contructors o (dependiendo de tu regla) constructores fluidos. Las relaciones de dependencia deben definirse en la inicialización de campo y no pueden crearse en los métodos @Before, ya que se ejecutan después de la aplicación de la regla. Para forzar el ordenamiento correcto de la ejecución de reglas, debe definir la cadena de reglas.

public class FolderRuleOrderingTest { 

    private TemporaryFolder folder = new TemporaryFolder(); 
    //assume, we have a rule that creates a testfile in a temporary folder 
    //we create a dependency relationship between file and folder, 
    //so that file depends on folder 
    private TemporaryFile file = new TemporaryFile(folder, "testfile.txt"); 

    //the rule chain ensures, the temporary folder is created before and removed 
    //after the testfile has been created and deleted (or whatever) 
    @Rule 
    public RuleChain chain= RuleChain.outerRule(folder).around(file)); 


    @Test 
    public void testFileExist() throws IOException { 
    assertTrue(file.getFile().exist()); 
    } 
    ... 
} 
Cuestiones relacionadas