Comment obtenir le chemin du répertoire src / test / resources dans JUnit?

275

Je sais que je peux charger un fichier depuis src / test / resources avec:

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

Mais comment puis-je obtenir le chemin complet vers le répertoire src / test / resources , c'est-à-dire que je ne veux pas charger un fichier, je veux juste connaître le chemin du répertoire?

Rory
la source
1
Par curiosité: pourquoi voulez-vous savoir?
fge
3
@fge doit le passer à l'objet en cours de test, qui l'utilise pour charger un fichier
Rory
5
L'accès direct aux fichiers dans votre répertoire de ressources est une mauvaise idée. Refactorisez votre code pour qu'il fonctionne sur un ordinateur à vapeur, ou demandez à votre test de créer d'abord une copie dans un dossier temporaire.
Oliver Charlesworth
4
@OliverCharlesworth Je suis d'accord sur les dossiers temporaires et j'utilise org.junit.rules.TemporaryFoldertout le temps ... mais ... pour copier à partir de tests / ressources, vous devez connaître, euh, son chemin!
mike rodent
1
@mikerodent - ce que je pense signifiait: lire la ressource via un flux d'entrée, puis l'écrire dans un fichier temporaire.
Oliver Charlesworth

Réponses:

204

Essayez de travailler avec la ClassLoaderclasse:

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

A ClassLoaderest responsable du chargement dans les classes. Chaque classe a une référence à a ClassLoader. Ce code renvoie un Filedu répertoire de ressources. L'appeler getAbsolutePath()renvoie son absolu Path.

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

ashosborne1
la source
35
Ce n'est pas nécessairement une bonne idée. Si la ressource est dans un pot, cela conduira à des moments tristes.
Oliver Charlesworth
1
@OliverCharlesworth Alors, que peut-on faire en cas de bocal?
Anmol Singh Jaggi
@AnmolSinghJaggi - Voir mon commentaire ci-dessous la question d'origine :)
Oliver Charlesworth
la construction de maven échoue lorsque j'utilise cette solution
firstpostcommenter
Ce sera aussi avec le nom de fichier
qwert_ukg
299

Vous n'avez pas besoin de jouer avec les chargeurs de classe. En fait, c'est une mauvaise habitude à prendre parce que les ressources du chargeur de classe ne sont pas objets java.io.File lorsqu'ils sont dans une archive jar.

Maven définit automatiquement le répertoire de travail actuel avant d'exécuter les tests, vous pouvez donc simplement utiliser:

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

resourcesDirectory.getAbsolutePath() renverra la valeur correcte si c'est ce dont vous avez vraiment besoin.

Je recommande de créer un src/test/datarépertoire si vous souhaitez que vos tests accèdent aux données via le système de fichiers. Cela montre clairement ce que vous faites.

Steve C
la source
4
nouveau fichier ("src / test / resources / fileXYZ"); ne fonctionnera pas. Ni d'Eclipse ni de Maven si vous mettez simplement cela dans un test JUnit.
seba.wagner
11
Cela fonctionne très bien de Maven. Dans eclipse, vous devrez définir le répertoire de travail actuel dans le lanceur de test, mais la ligne de commande maven le fait pour vous.
Steve C
4
Je ne pense pas. Et pourquoi feriez-vous cela si vous pouvez simplement faire un "nouveau fichier (getClass (). GetClassLoader (). GetResource (" fileNameXYZ.xml ")" sans avoir à configurer quoi que ce soit. Ni dans Eclipse ni dans Maven.
seba .wagner
10
Au contraire, pourquoi ne suivriez-vous pas les normes de votre utilitaire de génération? Surtout quand cela simplifie votre code. En utilisant IntelliJ ou Maven, il n'est pas nécessaire de définir le répertoire de travail. C'est évidemment la solution la plus simple, Eclipse étant une douleur comme toujours.
James Watkins
2
Pour la version IntelliJ 2014, je devais encore changer le répertoire de travail dans les configurations Run / Debug de la méthode / classe de test, comme @Steve C l'a mentionné.
a_secenthusiast
76

J'utiliserais simplement Path de Java 7

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

Propre et net!

Jean Valjean
la source
Ce même code fonctionnera-t-il exactement sous Windows? Le JavaDoc pour Paths.get(...)suggère (pour moi de toute façon) que ce ne sera pas le cas.
Steve C
@SteveC vous pouvez utiliser File.separatorconstant pour construire la chaîne à utiliser comme chemin
JeanValjean
1
Je le sais, mais c'est très moche. En revanche, new File("src/test/resources")fait la bonne chose sur toutes les plateformes.
Steve C
2
Pourquoi ne pas simplement utiliser Path resourceDirectory = Paths.get("src","test","resources");?
Navneeth
1
Hmm, Paths.get("src", "test", "resources")et Paths.get("src/test/resources")fonctionne bien sur Windows 10 pour moi. Qu'est-ce que je fais mal? =)
naXa
24

S'il s'agit d'un projet Spring, nous pouvons utiliser le code ci-dessous pour obtenir des fichiers du dossier src / test / resource .

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

J'ai un projet Maven3 utilisant JUnit 4.12 et Java8. Afin d'obtenir le chemin d'un fichier appelé myxml.xmlsous src/test/resources, je le fais à partir du scénario de test:

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

Testé sur Ubuntu 14.04 avec IntelliJ IDE. Référence ici .

Antony
la source
11

Tout le contenu src/test/resourcesest copié dans le target/test-classesdossier. Donc, pour obtenir un fichier à partir des ressources de test lors de la construction de maven, vous devez le charger à partir du test-classesdossier, comme ça:

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

Panne:

  1. getClass().getProtectionDomain().getCodeSource().getLocation().toURI()- vous donner l'URI target/test-classes.
  2. resolve(Paths.get("somefile"))- résout someFiledans le target/test-classesdossier.

La réponse originale est tirée de cette

Cerise
la source
8

Il existe des différences et des contraintes dans les options offertes par @Steve C et @ ashosborne1. Il faut les préciser, je crois.

Quand pouvons-nous utiliser File resourcesDirectory = new File("src/test/resources");:?

  • 1 Lorsque les tests doivent être exécutés via maven uniquement, mais pas via IDE.
  • 2.1 Quand les tests vont être exécutés via maven ou
  • 2.2 via IDE et un seul projet est importé dans IDE. (J'utilise le terme «importé», car il est utilisé dans IntelliJ IDEA. Je pense que les utilisateurs d'éclipse importent également leur projet maven). Cela fonctionnera, car le répertoire de travail lorsque vous exécutez des tests via IDE est le même que votre projet.
  • 3.1 Quand les tests vont être exécutés via maven ou
  • 3.2 via IDE, et plusieurs projets sont importés dans IDE (lorsque vous n'êtes pas étudiant, vous importez généralement plusieurs projets), ET avant d'exécuter des tests via IDE, vous configurez manuellement le répertoire de travail pour vos tests. Ce répertoire de travail doit faire référence à votre projet importé qui contient les tests. Par défaut, le répertoire de travail de tous les projets importés dans IDE n'en est qu'un. C'est probablement une restriction de IntelliJ IDEAseulement, mais je pense que tous les IDE fonctionnent comme ça. Et cette configuration qui doit être faite manuellement, n'est pas bonne du tout. Travailler avec plusieurs tests existant dans différents projets maven, mais importés dans un grand projet «IDE», nous obligent à nous en souvenir et ne permettent pas de se détendre et de profiter de votre travail.

La solution offerte par @ ashosborne1 (personnellement, je préfère celle-ci) nécessite 2 exigences supplémentaires qui doivent être effectuées avant d'exécuter des tests. Voici une liste d'étapes pour utiliser cette solution:

  • Créez un dossier de test («teva») et un fichier («readme») à l'intérieur de «src / test / resources /»:

    src / test / resources / teva / readme

    Le fichier doit être créé dans le dossier de test, sinon cela ne fonctionnera pas. Maven ignore les dossiers vides.

  • Créez au moins une fois le projet via mvn clean install. Il exécutera également des tests. Il peut être suffisant d'exécuter uniquement votre classe / méthode de test via maven sans construire un projet entier. Par conséquent, vos ressources de test seront copiées dans des classes de test, voici un chemin:target/test-classes/teva/readme

  • Après cela, vous pouvez accéder au dossier à l'aide de code, déjà proposé par @ ashosborne1 (je suis désolé, je n'ai pas pu modifier correctement ce code dans cette liste d'éléments):

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

Vous pouvez maintenant exécuter votre test via IDE autant de fois que vous le souhaitez. Jusqu'à ce que vous exécutiez mvn clean. Il supprimera le dossier cible.

La création d'un fichier dans un dossier de test et l'exécution de maven pour la première fois, avant d'exécuter des tests via IDE, sont des étapes nécessaires. Sans ces étapes, si vous venez de créer des ressources de test dans votre IDE, puis d'écrire test et de l'exécuter via IDE uniquement, vous obtiendrez une erreur. L'exécution de tests via mvn copie les ressources de test dans target / test-classes / teva / readme et elles deviennent accessibles pour un chargeur de classe.

Vous pouvez vous demander, pourquoi ai-je besoin d'importer plus d'un projet maven dans IDE et pourquoi tant de choses compliquées? Pour moi, l'une des principales motivations: garder les fichiers liés à l'IDA loin du code. Je crée d'abord un nouveau projet dans mon IDE. C'est un faux projet, c'est juste un détenteur de fichiers liés à l'IDE. Ensuite, j'importe des projets maven déjà existants. Je force ces projets importés à conserver les fichiers IDEA uniquement dans mon faux projet d'origine. Par conséquent, je ne vois pas de fichiers liés à l'IDE dans le code. SVN ne devrait pas les voir (ne proposez pas de configurer svn / git pour ignorer ces fichiers, s'il vous plaît). C'est aussi très pratique.

Alexandr
la source
Salut Alexandr, je suis en difficulté avec le fichier de ressources dans target / classes et src / main / resource et vous semblez le seul à en parler. J'ai d'abord des fichiers sur src / main / resource, après le projet de construction, il copie ces fichiers dans target / classes. Et à partir de là, getClass (). GetClassLoader (). GetResource (fileName) ne fonctionne que sur le dossier cible alors que je veux travailler sur src / main. Pouvez-vous me donner un lien quelque part expliquer le mécanisme du fichier getResource? comment configurer le dossier de ressources? Tks: D
Huy Hóm Hỉnh
2
@Huy Hóm Hỉnh, je recommanderais de ne pas le faire. Je crains que vous n'alliez dans la mauvaise direction. Il y a certains endroits où se trouvent les fichiers de ressources, les endroits sont connus pour tous les autres. Plus facile à maintenir de tels projets. Même pour vous, ce sera plus facile, il vous suffit de comprendre la structure des projets maven. Mais pour sûr, vous pouvez configurer l'emplacement des ressources par défaut avec [ maven.apache.org/plugins/maven-resources-plugin/examples/…
Alexandr
@ HuyHómHỉnh, Jetez également un œil à la solution ici: stackoverflow.com/questions/23289098/… Mais pour vous configurer src / main en tant que ressource ... Essayez de l'éviter, il semble que vous faites quelque chose de mal.
Alexandr
hm. Pourriez-vous expliquer ce qui ne va pas .gitignore? Il semble également que IDEA exécute Maven automatiquement lors de l'exécution des tests (et définit le répertoire de travail correct par défaut $MODULE_DIR$). Il n'est donc pas nécessaire d'exécuter mvn testmanuellement avant cela, tout fonctionne bien à la fois avec Maven et IDEA avec just "src/test/resources/somefile.txt".
Alex P.
5

La solution la plus simple et la plus propre que j'utilise, supposons que le nom de la classe de test soit TestQuery1et qu'il y ait un resourcesrépertoire dans votre testdossier comme suit:

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

Pour obtenir l'URI de TestQuery1do:

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

Pour obtenir l'URI de l'un des fichiers TestQuery1, procédez comme suit:

File exampleDir = new File(currentTestResourceFolder.toURI());
URI queryJSONFileURI = exampleDir.toURI().resolve("query.json");
Noor
la source
1
Pas de soucis, en fait merci pour votre aide !! La bonne chose est que la suppression de votre réponse, je suis en mesure de supprimer la question. Ouais, assez frustré ici aussi, mais de toute façon merci !! Bonsoir :)
Noor
1

Vous ne pouvez pas utiliser un fichier d'un dossier de ressources pour les tests dans un cas courant. La raison en est que les fichiers de ressources du dossier de ressources sont stockés dans un bocal. Ils n'ont donc pas de chemin réel dans le système de fichiers.

La solution la plus simple peut être:

  1. Copiez un fichier des ressources dans le dossier temporaire et obtenez un chemin d'accès à ce fichier temporaire.
  2. Faites des tests en utilisant un chemin temporaire.
  3. Supprimez le fichier temporaire.

TemporaryFolderfrom JUnitpeut être utilisé pour créer des fichiers temporaires et les supprimer une fois le test terminé. Les classes de la guavabibliothèque sont utilisées pour copier un dossier de ressources sous forme de fichier.

Veuillez noter que si nous utilisons un sous-dossier dans le dossier des ressources, comme goodcelui-ci, nous n'avons pas besoin d'ajouter /le début du chemin d'accès aux ressources.

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
la source
0

Utilisez ce qui suit pour injecter Hibernate avec Spring dans vos tests unitaires:

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

Si vous n'avez pas le hibernate.cfg.xmlprésent dans votre src/test/resourcesdossier, il retombera automatiquement dans celui de votre src/main/resourcesdossier.

sourcils blancs
la source
0

Utilisez .getAbsolutePath () sur votre objet File.

getClass().getResource("somefile").getFile().getAbsolutePath()
GreatDantone
la source
getFile retourne l'instance de chaîne non FIle
Almas Abdrazak
@AlmasAbdrazak GreatDantone ne dit pas que getFile()renvoie une instance de fichier. Il dit qu'il getAbsolutePath()est utilisé sur une instance d'un objet File.
menteith
@menteith Selon son code, il appelle getFile () puis getAbsolutePath () sur getFile () mais getFile () renvoie String et vous ne pouvez pas appeler getAbsolutePath () sur l'objet String
Almas Abdrazak
0

Avec Spring, vous pouvez facilement le lire à partir du dossier des ressources (principal / ressources ou test / ressources):

Par exemple, créez un fichier: 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
la source
0
List<String> lines = Files.readAllLines(Paths.get("src/test/resources/foo.txt"));
lines.forEach(System.out::println);
zhuguowei
la source