¿Cómo obtener la ruta del directorio src / test / resources en JUnit?

275

Sé que puedo cargar un archivo de src / test / resources con:

getClass().getResource("somefile").getFile()

Pero, ¿cómo puedo obtener la ruta completa al directorio src / test / resources , es decir, no quiero cargar un archivo, solo quiero saber la ruta del directorio?

Rory
fuente
1
Por curiosidad: ¿por qué quieres saber?
fge
3
@fge necesita pasarlo al objeto bajo prueba, que lo usa para cargar un archivo
Rory
55
El acceso directo a los archivos de su directorio de recursos es una mala idea. Refactorice su código para operar en Steam, o haga que su prueba cree primero una copia en un TemporaryFolder.
Oliver Charlesworth
44
@OliverCharlesworth Estoy de acuerdo con las carpetas temporales y uso org.junit.rules.TemporaryFoldertodo el tiempo ... pero ... para copiar de la prueba / recursos, ¡debes saber, er, su ruta!
Mike roedor
1
@mikerodent: lo que creo que significaba era: leer el recurso a través de un flujo de entrada y luego escribirlo en un archivo temporal.
Oliver Charlesworth

Respuestas:

204

Intenta trabajar con la ClassLoaderclase:

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("somefile").getFile());
System.out.println(file.getAbsolutePath());

A ClassLoaderes responsable de cargar en las clases. Cada clase tiene una referencia a a ClassLoader. Este código devuelve un Filedesde el directorio de recursos. Invocarlo getAbsolutePath()devuelve su absoluto Path.

Javadoc para ClassLoader: http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html

ashosborne1
fuente
34
Esto no es necesariamente una buena idea. Si el recurso está en un frasco, esto conducirá a momentos tristes.
Oliver Charlesworth
1
@OliverCharlesworth Entonces, ¿qué se puede hacer en caso de jar?
Anmol Singh Jaggi
@AnmolSinghJaggi - Vea mi comentario debajo de la pregunta original :)
Oliver Charlesworth
maven build falla cuando uso esta solución
firstpostcommenter
También estará con el nombre del archivo
qwert_ukg
299

No necesita meterse con cargadores de clases. De hecho, es un mal hábito entrar porque los recursos del cargador de clases no son objetos java.io.File cuando están en un archivo jar.

Maven establece automáticamente el directorio de trabajo actual antes de ejecutar pruebas, por lo que puede usar:

    File resourcesDirectory = new File("src/test/resources");

resourcesDirectory.getAbsolutePath() devolverá el valor correcto si eso es lo que realmente necesita.

Recomiendo crear un src/test/datadirectorio si desea que sus pruebas accedan a los datos a través del sistema de archivos. Esto deja en claro lo que estás haciendo.

Steve C
fuente
44
nuevo archivo ("src / test / resources / fileXYZ"); no trabajará. Ni de Eclipse ni de Maven si simplemente lo pones en una prueba JUnit.
seba.wagner
11
Funciona bien de Maven. En eclipse, deberá establecer el directorio de trabajo actual en el corredor de prueba, pero la línea de comando maven lo hace por usted.
Steve C
44
No lo creo. ¿Y por qué haría eso si puede hacer simplemente un "nuevo archivo (getClass (). GetClassLoader (). GetResource (" fileNameXYZ.xml ")" sin necesidad de configurar nada? Ni en Eclipse ni en Maven.
seba .wagner
10
Por el contrario, ¿por qué no seguirías los estándares de tu utilidad de compilación? Especialmente cuando simplifica tu código. Usando IntelliJ o Maven, no hay necesidad de establecer un directorio de trabajo. Obviamente, esta es la solución más simple, con Eclipse siendo una molestia como siempre.
James Watkins
2
Para la versión IntelliJ 2014, todavía tenía que cambiar el directorio de trabajo en las configuraciones Ejecutar / Depurar del método / clase de prueba, como se mencionó en @Steve C.
a_secenthusiast
76

Simplemente usaría Pathde Java 7

Path resourceDirectory = Paths.get("src","test","resources");

¡Limpio y ordenado!

JeanValjean
fuente
¿Funcionará exactamente este mismo código en Windows? El JavaDoc para Paths.get(...)sugiere (para mí de todos modos) que no lo hará.
Steve C
@SteveC puede usar File.separatorconstante para construir la cadena que se utilizará como ruta
JeanValjean
1
Lo sé, pero es muy feo. Por el contrario, new File("src/test/resources")hace lo correcto en todas las plataformas.
Steve C
2
¿Por qué no solo usar Path resourceDirectory = Paths.get("src","test","resources");?
Navneeth
1
Hmm, Paths.get("src", "test", "resources")y Paths.get("src/test/resources")funciona bien en Windows 10 para mí. ¿Qué estoy haciendo mal? =)
naXa
24

Si se trata de un proyecto de primavera, podemos usar el siguiente código para obtener archivos de la carpeta src / test / resource .

File file = ResourceUtils.getFile(this.getClass().getResource("/some_file.txt"));
Paramesh Korrakuti
fuente
14

Tengo un proyecto Maven3 usando JUnit 4.12 y Java8. Para obtener la ruta de un archivo llamado myxml.xmldebajo src/test/resources, hago esto desde el caso de prueba:

@Test
public void testApp()
{
    File inputXmlFile = new File(this.getClass().getResource("/myxml.xml").getFile());
    System.out.println(inputXmlFile.getAbsolutePath());
    ...
}

Probado en Ubuntu 14.04 con IntelliJ IDE. La referencia aquí .

Antonio
fuente
11

Todo el contenido src/test/resourcesse copia en la target/test-classescarpeta. Entonces, para obtener el archivo de los recursos de prueba durante la compilación de Maven, debe cargarlo desde la test-classescarpeta, así:

Paths.get(
    getClass().getProtectionDomain().getCodeSource().getLocation().toURI()
).resolve(
    Paths.get("somefile")
).toFile()

Descompostura:

  1. getClass().getProtectionDomain().getCodeSource().getLocation().toURI() - darle URI a target/test-classes .
  2. resolve(Paths.get("somefile"))- Resuelve someFilea la target/test-classescarpeta.

La respuesta original se toma de esto

Cereza
fuente
8

Existen diferencias y restricciones en las opciones ofrecidas por @Steve C y @ ashosborne1. Deben especificarse, creo.

¿Cuándo podemos usar File resourcesDirectory = new File("src/test/resources");:?

  • 1 Cuando las pruebas se ejecutarán solo a través de Maven pero no a través de IDE.
  • 2.1 Cuando las pruebas se ejecutarán a través de Maven o
  • 2.2 a través de IDE y solo se importa un proyecto a IDE. (Uso el término "importado", porque se usa en IntelliJ IDEA. Creo que los usuarios de eclipse también importan su proyecto maven). Esto funcionará, porque el directorio de trabajo cuando ejecuta pruebas a través de IDE es el mismo que su proyecto.
  • 3.1 Cuando las pruebas se ejecutarán a través de Maven o
  • 3.2 a través de IDE, y se importan más de un proyecto a IDE (cuando no es estudiante, generalmente importa varios proyectos), y antes de ejecutar pruebas a través de IDE, configura manualmente el directorio de trabajo para sus pruebas. Ese directorio de trabajo debe referirse a su proyecto importado que contiene las pruebas. Por defecto, el directorio de trabajo de todos los proyectos importados en IDE es solo uno. Probablemente solo sea una restricción IntelliJ IDEA, pero creo que todos los IDE funcionan así. Y esta configuración que debe hacerse manualmente, no es buena en absoluto. Trabajando con varias pruebas existentes en diferentes proyectos de Maven, pero importados en un gran proyecto "IDE", nos obligan a recordar esto y no permitimos relajarnos y disfrutar de su trabajo.

La solución ofrecida por @ ashosborne1 (personalmente prefiero esta) requiere 2 requisitos adicionales que deben realizarse antes de ejecutar las pruebas. Aquí hay una lista de pasos para usar esta solución:

  • Cree una carpeta de prueba ("teva") y un archivo ("readme") dentro de "src / test / resources /":

    src / test / resources / teva / readme

    El archivo debe crearse en la carpeta de prueba, de lo contrario, no funcionará. Maven ignora las carpetas vacías.

  • Al menos una vez construir el proyecto a través de mvn clean install. También ejecutará pruebas. Puede ser suficiente ejecutar solo su clase / método de prueba a través de Maven sin construir un proyecto completo. Como resultado, sus recursos de prueba se copiarán en clases de prueba, aquí hay una ruta:target/test-classes/teva/readme

  • Después de eso, puede acceder a la carpeta usando el código, ya ofrecido por @ ashosborne1 (lo siento, no pude editar este código dentro de esta lista de elementos correctamente):

public static final String TEVA_FOLDER = "teva"; ... 
URL tevaUrl = YourTest.class.getClassLoader().getResource(TEVA_FOLDER); 
String tevaTestFolder = new File(tevaUrl.toURI()).getAbsolutePath();

Ahora puede ejecutar su prueba a través de IDE tantas veces como lo desee. Hasta que corras mvn limpio. Caerá la carpeta de destino.

Los pasos necesarios para crear un archivo dentro de una carpeta de prueba y ejecutar maven por primera vez, antes de ejecutar las pruebas a través de IDE. Sin estos pasos, si solo en su IDE crea recursos de prueba, luego escribe la prueba y la ejecuta solo a través de IDE, obtendrá un error. La ejecución de pruebas a través de mvn copia los recursos de prueba en target / test-classes / teva / readme y se vuelven accesibles para un cargador de clases.

Puede preguntar, ¿por qué necesito importar más de un proyecto Maven en IDE y por qué tantas cosas complicadas? Para mí, una de las principales motivaciones: mantener los archivos relacionados con IDA lejos del código. Primero creo un nuevo proyecto en mi IDE. Es un proyecto falso, que es solo un titular de archivos relacionados con IDE. Luego, importo proyectos maven ya existentes. Obligo a estos proyectos importados a mantener archivos IDEA solo en mi proyecto falso original. Como resultado, no veo archivos relacionados con IDE entre el código. SVN no debería verlos (no ofrezca configurar svn / git para ignorar dichos archivos, por favor). También es muy conveniente.

Alexandr
fuente
Hola Alexandr, estoy en problemas con el archivo de recursos en target / classes y src / main / resource y pareces el único que habla de eso. Primero tengo archivos en src / main / resource, después del proyecto de compilación, copia estos archivos a target / classes. Y a partir de esto, getClass (). GetClassLoader (). GetResource (fileName) solo funciona en la carpeta de destino, mientras que quiero trabajar en src / main. ¿Me puede dar un enlace en alguna parte para explicar el mecanismo del archivo getResource? ¿Cómo configurar la carpeta de recursos? Tks: D
Huy Hóm Hỉnh
2
@Huy Hóm Hỉnh, recomendaría no hacerlo. Me temo que va en la dirección equivocada. Hay ciertos lugares donde se encuentran los archivos de recursos, los lugares son conocidos por todos los demás. Más fácil de mantener tales proyectos. Incluso para ti será más fácil, solo necesitas entender la estructura de los proyectos de Maven. Pero seguro, puede configurar la ubicación de recursos predeterminada con [ maven.apache.org/plugins/maven-resources-plugin/examples/…
Alexandr
@ HuyHómHỉnh, también eche un vistazo a la solución aquí: stackoverflow.com/questions/23289098/… Pero para configurar su src / main como un recurso ... Intente evitarlo, parece que está haciendo algo mal.
Alexandr el
hm. ¿Podría explicar qué le pasa .gitignore? También parece que IDEA ejecuta Maven automáticamente cuando ejecuta pruebas (y establece el directorio de trabajo correcto de forma predeterminada $MODULE_DIR$). Por lo tanto, no es necesario ejecutar mvn testmanualmente antes de eso, todo funciona bien tanto de Maven como de IDEA con solo "src/test/resources/somefile.txt".
Alex P.
5

La solución más simple y limpia que uso, supongamos que el nombre de la clase de prueba es TestQuery1y hay un resourcesdirectorio en su testcarpeta de la siguiente manera:

├── java
   └── TestQuery1.java
└── resources
    └── TestQuery1
        ├── query.json
        └── query.rq

Para obtener el URI de TestQuery1do:

URL currentTestResourceFolder = getClass().getResource("/"+getClass().getSimpleName());

Para obtener el URI de uno de los archivos TestQuery1, haga lo siguiente:

File exampleDir = new File(currentTestResourceFolder.toURI());
URI queryJSONFileURI = exampleDir.toURI().resolve("query.json");
Noor
fuente
1
No te preocupes, de hecho, gracias por tu ayuda! Lo bueno es que al eliminar su respuesta, puedo eliminar la pregunta. Sí, bastante frustrado aquí también, pero de todos modos, ¡gracias! Buenas noches :)
Noor
1

No puede usar un archivo de una carpeta de recursos para pruebas en un caso común. La razón es que los archivos de recursos en la carpeta de recursos se almacenan dentro de un jar. Por lo tanto, no tienen una ruta real en el sistema de archivos.

La solución más simple puede ser:

  1. Copie un archivo de los recursos a la carpeta temporal y obtenga una ruta a ese archivo temporal.
  2. Haz pruebas usando una ruta temporal.
  3. Eliminar el archivo temporal.

TemporaryFolderfrom JUnitse puede usar para crear archivos temporales y eliminarlos después de completar la prueba. Clases deguava biblioteca se utilizan para copiar una carpeta de recursos de formulario de archivo.

Tenga en cuenta que si usamos una subcarpeta en la carpeta de recursos, como gooduna, no tenemos que agregar el encabezado /a la ruta del recurso.

public class SomeTest {

    @Rule
    public TemporaryFolder tmpFolder = new TemporaryFolder();


    @Test
    public void doSomethinge() throws IOException {
        File file = createTmpFileFromResource(tmpFolder, "file.txt");
        File goodFile = createTmpFileFromResource(tmpFolder, "good/file.txt");

        // do testing here
    }

    private static File createTmpFileFromResource(TemporaryFolder folder,
                                                  String classLoaderResource) throws IOException {
        URL resource = Resources.getResource(classLoaderResource);

        File tmpFile = folder.newFile();
        Resources.asByteSource(resource).copyTo(Files.asByteSink(tmpFile));
        return tmpFile;
    }

}
v.ladynev
fuente
0

Use lo siguiente para inyectar Hibernate con Spring en sus pruebas unitarias:

@Bean
public LocalSessionFactoryBean getLocalSessionFactoryBean() {
    LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
    localSessionFactoryBean.setConfigLocation(new ClassPathResource("hibernate.cfg.xml"));
    localSessionFactoryBean.setPackagesToScan("com.example.yourpackage.model");
    return localSessionFactoryBean;
}

Si no tiene el hibernate.cfg.xmlpresente en su src/test/resourcescarpeta, volverá automáticamente al que está en su src/main/resourcescarpeta.

ceja
fuente
0

Use .getAbsolutePath () en su objeto File.

getClass().getResource("somefile").getFile().getAbsolutePath()
GreatDantone
fuente
getFile return String instancia no archivo
Almas Abdrazak
@AlmasAbdrazak GreatDantone no dice que getFile()devuelva una instancia de archivo. Él dice que getAbsolutePath()se usa en una instancia del objeto File.
menteith
@menteith Según su código, llama a getFile () y luego a getAbsolutePath () en getFile () pero getFile () devuelve String y no se puede llamar a getAbsolutePath () en el objeto String
Almas Abdrazak
0

Con Spring puedes leerlo fácilmente desde la carpeta de recursos (ya sea main / resources o test / resources):

Por ejemplo, crea un archivo: test/resources/subfolder/sample.json

@Test
public void testReadFile() {
    String json = this.readFile("classpath:subfolder/sample.json");
    System.out.println(json);
}

public String readFile(String path) {
    try {
        File file = ResourceUtils.getFile(path);
        return new String(Files.readAllBytes(file.toPath()));
    } catch (IOException e) {
        e.printStackTrace();
    }

    return null;
}
MevlütÖzdemir
fuente
0
List<String> lines = Files.readAllLines(Paths.get("src/test/resources/foo.txt"));
lines.forEach(System.out::println);
zhuguowei
fuente