¿Cuál es la forma correcta de escribir en un archivo temporal durante las pruebas unitarias con Maven?

7 minutos de lectura

avatar de usuario
bret ryan

Escribí una prueba de unidad que escribe un archivo en el sistema de archivos, sin dar ninguna ruta que escriba en el directorio de trabajo; entonces, si se ejecuta desde el directorio del proyecto, escribe en la raíz del proyecto, si está en el directorio principal del proyecto, escribe en el directorio raíz principal.

Entonces, ¿cuál es la forma correcta de escribir en el directorio de destino? ¿Posiblemente un directorio dentro del directorio de destino?

Si simplemente especifico target/ con el archivo, escribirá en el destino de los proyectos principales en lugar del destino de los proyectos.

ACTUALIZAR: De hecho, quiero el archivo después de que finalice la prueba. El archivo es para un formato de extracción para terceros que debe enviarse a los terceros. La prueba se puede activar/desactivar para permitirme ejecutarla solo si el formato del archivo cambia para volver a aprobarlo. No es un gran problema dónde va el archivo, pero me gustaría algo que sea fácil de encontrar.

avatar de usuario
mamá

Podrías intentar usar Carpeta temporal JUnit @Rule como se describe aquí

los Carpeta temporal crea una carpeta en el directorio de archivos temporales predeterminado especificado por la propiedad del sistema java.io.tmpdir. El método newFile crea un nuevo archivo en el directorio temporal y newFolder crea una nueva carpeta.

Cuando finaliza el método de prueba, JUnit elimina automáticamente todos los archivos y directorios incluidos en la carpeta temporal. JUnit garantiza eliminar los recursos, ya sea que la prueba pase o falle.


Después de la pregunta actualizada

Puede cambiar el directorio de trabajo utilizado por maven-surefire-plugin.

<plugins>
    [...]
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.12.3</version>
        <configuration>
          <workingDirectory>${project.build.directory}</workingDirectory>
        </configuration>
      </plugin>
    [...]
</plugins>

Puede cambiar ese directorio de trabajo a cualquier cosa que necesite para sus pruebas como ${project.build.directory}/my_special_dir/.

El directorio de trabajo en el complemento surefire solo afecta las pruebas que se ejecutan y SOLO para las pruebas realizadas por maven. Si ejecuta sus pruebas desde dentro de un IDE, el directorio de trabajo será otra cosa.

  • Gracias maba, este es un problema similar a Bohemian, el archivo termina en un lugar oscuro. De hecho, quiero el archivo después de que finalice la prueba.

    –Bret Ryan

    13 de septiembre de 2012 a las 6:38

  • @BrettRyan OK, actualizado con cómo cambiar el directorio de trabajo para el complemento de éxito seguro. Eso debería hacer el truco.

    – mamá

    13 de septiembre de 2012 a las 6:50

  • Fantástico, gracias maba, eso es perfecto y siempre será consistente en todas las máquinas en las que se ejecuta la prueba.

    –Bret Ryan

    13 de septiembre de 2012 a las 8:22

  • Gracias por dejar la respuesta original. Eso es lo que necesitaba.

    – yellavon

    17/04/2014 a las 16:40

  • JUNIT no garantiza la eliminación automática, debe hacerlo @Rule public TemporaryFolder folder = TemporaryFolder.builder().assureDeletion().build();

    – vimal krishna

    11 de enero de 2017 a las 15:05

avatar de usuario
bohemio

No hay necesidad de reinventar la rueda…

El JDK proporciona una forma de crear un archivo temporal y una forma de eliminarlo automáticamente al salir:

File file = File.createTempFile( "some-prefix", "some-ext");
file.deleteOnExit();

Use el archivo y se eliminará automáticamente cuando finalice su prueba. Eso es todo al respecto.

Para especificar el directorio que se usará para los archivos temporales, use el método sobrecargado:

File file = File.createTempFile( "prefix", "ext", new File("/some/dir/path"));

  • Gracias Bohemian, en realidad quiero que el archivo permanezca después de la salida, para poder enviárselo al proveedor. Supongo que el directorio temporal del sistema está bien, aunque esperaba tenerlo en el directorio de destino.

    –Bret Ryan

    13 de septiembre de 2012 a las 6:32

  • Acabo de intentar esto y resulta que el archivo está en un lugar tan oscuro que no sería prudente usarlo. terminó en /var/folders/xf/scvh7yr11m1glr4b663n1hcsnv5lf0/T/test2614442099335581603.xml

    –Bret Ryan

    13 de septiembre de 2012 a las 6:35

  • @BrettRyan No hay problema: puede especificar el directorio que se usa para los archivos temporales; vea la respuesta editada

    – bohemio

    13 de septiembre de 2012 a las 7:13

  • Gracias Bohemian, veo el mérito de poder configurar el directorio temporal, aunque me gusta la capacidad de tener esto en una ubicación confiable debajo del directorio de destino en lugar de requerir una ubicación específica existente en la máquina.

    –Bret Ryan

    13 de septiembre de 2012 a las 8:24

avatar de usuario
NubladoMármol

Escribiría una rutina que determine dónde se debe escribir el archivo, lo que unificaré después, en general, trato de evitar (en la medida de lo posible) el acceso a datos persistentes en pruebas unitarias, como el archivo IO o el acceso a la base de datos, esto tiene razones de rendimiento y otras también .

Echa un vistazo a esta respuesta: https://stackoverflow.com/a/8032504/395659

  • Gracias OD, nunca había tenido que hacer tal cosa hasta ahora. Escribí la prueba para escribir un archivo que se enviará a otros proveedores en código de producción. Mi prueba escribe el archivo en el disco para que lo envíe a los proveedores para obtener la aprobación. Una vez aprobada, la prueba no será necesaria, pero podría ser útil más adelante cuando algo cambie y necesite “volver a aprobar” la salida.

    –Bret Ryan

    13 de septiembre de 2012 a las 6:19

  • pero ¿por qué está utilizando una “prueba unitaria” para tal propósito? Creo que incluso tener una clase separada con el método main() para tal propósito es aún más apropiado que abusar de la prueba unitaria

    – Adrián Shum

    13 de septiembre de 2012 a las 6:42

Querrá poder ejecutar sus pruebas tanto desde un IDE como desde Maven, por lo que la mejor práctica es escribir sus pruebas para que no supongan que se están ejecutando dentro de Maven.

Una de las mejores formas de manejar archivos temporales es usando reglas conjuntas. Esto le permite confiar en la regla para limpiar por usted.

Para decirlo de antemano, estoy totalmente en contra de hacer tales cosas en la prueba unitaria. Realmente no he probado esto, pero debería funcionar:

Suponga que está utilizando un complemento seguro, del documento que cita que puede acceder al directorio base del proyecto bajo prueba por System.getProperty("basedir"). Consíguelo y crea archivos en basedir/target.

Una forma más “apropiada” (ya que podemos tener la posibilidad de que hayamos configurado el directorio de salida en otra cosa, puede cambiar la configuración segura del complemento a algo como esto:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <systemPropertyVariables>
            <myOutDir>${project.build.outputDirectory}</myOutDir>
        </systemPropertyVariables>
    </configuration>
</plugin>

Entonces puede obtener el directorio de salida real por System.getProperty("myOutDir") en tu prueba.

avatar de usuario
AlexR

Los archivos temporales deben crearse en el directorio temporal. Recuperarlo mediante llamada System.getProperty("java.io.tmpdir")

El archivo temporal debe ser temporal, es decir, debe eliminarse cuando no se necesite. Para lograr esto no olvides borrarlo en finally bloque o en el código que se ejecuta después de la prueba, es decir:

File tmpFile = ...
try {
   // deal with tempFile
} finally {
    tempFile.delete();
}

y/o

public class MyTestCase {
    private File tmpFile = null;

    @Before
    public void setUp() {
        tmpFile = ...;
    }

    @Test
    public void setUp() {
        // deal with tmpFile
    }

    @After
    public void setUp() {
        tmpFile.delete();
    }
}

Usar File.createTempFile(String prefix, String suffix) si es posible, es decir, puede usar un archivo con un nombre especial generado por createTempFile().

Usar file.deleteOnExit(). Esto crea un enlace que elimina el archivo automáticamente cuando se termina la JVM. El archivo permanecerá solo si JVM se eliminó con kill -9por lo que no tuvo la oportunidad de ejecutar el código de apagado.

avatar de usuario
dpelisek

Desde JUnit 5 puedes usar @TempDir. Se eliminará (incluido su contenido) después de la(s) prueba(s).

ya sea un directorio temporal para cada prueba:

@Test
void testWithTempFiles(@TempDir Path tempDir) 
    Path file = dir.resolve("temp_file.txt");
    ...
}

o uno solo para todas las pruebas de la clase:

@TempDir
static Path tempDir

@Test
void testWithTempFiles() 
    Path file = dir.resolve("temp_file.txt");
    ...
}

¿Ha sido útil esta solución?