Jak uzyskać ścieżkę do katalogu src / test / resources w JUnit?

275

Wiem, że mogę załadować plik z src / test / resources za pomocą:

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

Ale w jaki sposób można uzyskać pełną ścieżkę do src / test / zasobów katalogu , to znaczy nie chcę, aby załadować plik, po prostu chcę znać ścieżkę katalogu?

Rory
źródło
1
Z ciekawości: po co chcesz wiedzieć?
fge
3
@ fge musi przekazać go do testowanego obiektu, który używa go do załadowania pliku
Rory
5
Bezpośredni dostęp do plików w katalogu zasobów to zły pomysł. Zmodyfikuj kod, aby działał na parze, lub poproś, aby test utworzył najpierw kopię w folderze tymczasowym.
Oliver Charlesworth
4
@OliverCharlesworth Zgadzam się na temat folderów tymczasowych i używam org.junit.rules.TemporaryFoldercały czas ... ale ... aby skopiować z testu / zasobów, musisz wiedzieć, er, jego ścieżka!
Mike gryzoni
1
@mikerodent - miałem na myśli: przeczytaj zasób przez strumień wejściowy, a następnie zapisz go do pliku tymczasowego.
Oliver Charlesworth

Odpowiedzi:

204

Spróbuj pracować z ClassLoaderklasą:

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

A ClassLoaderodpowiada za ładowanie w klasach. Każda klasa ma odniesienie do ClassLoader. Ten kod zwraca a Filez katalogu zasobów. Wywołanie getAbsolutePath()go zwraca wartość absolutną Path.

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

ashosborne1
źródło
34
To niekoniecznie dobry pomysł. Jeśli zasób znajduje się w słoiku, doprowadzi to do smutnych chwil.
Oliver Charlesworth
1
@OliverCharlesworth Więc co można zrobić w przypadku słoika?
Anmol Singh Jaggi
@AnmolSinghJaggi - Zobacz mój komentarz poniżej oryginalnego pytania :)
Oliver Charlesworth
kompilacja maven kończy się niepowodzeniem, gdy korzystam z tego rozwiązania
firstpostcommenter
Będzie też z nazwą pliku
qwert_ukg
299

Nie musisz zadzierać z modułami ładującymi klasy. W rzeczywistości jest to zły nawyk wchodzenia w to, ponieważ zasoby modułu ładującego klasy nie są obiektami java.io.File, gdy znajdują się w archiwum jar.

Maven automatycznie ustawia bieżący katalog roboczy przed uruchomieniem testów, więc możesz po prostu użyć:

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

resourcesDirectory.getAbsolutePath() zwróci prawidłową wartość, jeśli tego naprawdę potrzebujesz.

Polecam utworzenie src/test/datakatalogu, jeśli chcesz, aby twoje testy miały dostęp do danych przez system plików. To wyjaśnia, co robisz.

Steve C.
źródło
4
nowy plik („src / test / resources / fileXYZ”); nie będzie działać. Ani z Eclipse, ani z Maven, jeśli po prostu poddasz to testowi JUnit.
seba.wagner
11
Działa dobrze z Maven. W środowisku Eclipse będziesz musiał ustawić bieżący katalog roboczy w programie testującym, ale maven z linii poleceń to zrobi za ciebie.
Steve C,
4
Nie wydaje mi się I dlaczego miałbyś to zrobić, jeśli możesz zrobić po prostu „nowy plik (getClass (). GetClassLoader (). GetResource („ fileNameXYZ.xml ”)” bez potrzeby konfigurowania czegokolwiek. Ani w Eclipse, ani w Maven.
seba .wagner
10
Dlaczego raczej nie miałbyś przestrzegać standardów narzędzia do budowania? Zwłaszcza gdy upraszcza twój kod. Korzystając z IntelliJ lub Maven, nie ma potrzeby ustawiania katalogu roboczego. Jest to oczywiście najprostsze rozwiązanie, ponieważ Eclipse jest bólem jak zawsze.
James Watkins
2
W przypadku wersji IntelliJ 2014 musiałem nadal zmieniać katalog roboczy w konfiguracjach Run / Debug metody / klasy testowej, jak wspomniano w @Steve C.
a_secenthusiast
76

Po prostu użyłbym Pathz Java 7

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

Schludnie i czysto!

Jean Valjean
źródło
Czy ten sam kod będzie działał w systemie Windows? JavaDoc dla Paths.get(...)sugeruje (w każdym razie dla mnie), że tak nie będzie.
Steve C
@ SteveC możesz użyć File.separatorstałej do zbudowania łańcucha, który będzie używany jako ścieżka
JeanValjean
1
Wiem o tym, ale to jest bardzo brzydkie. Przeciwnie, new File("src/test/resources")robi to dobrze na wszystkich platformach.
Steve C
2
Dlaczego nie po prostu użyć Path resourceDirectory = Paths.get("src","test","resources");?
Navneeth,
1
Hmm, Paths.get("src", "test", "resources")i Paths.get("src/test/resources")działaj dobrze dla Windows 10 dla mnie. Co ja robię źle? =)
naXa
24

Jeśli jest to projekt wiosenny, możemy użyć poniższego kodu, aby pobrać pliki z folderu src / test / resource .

File file = ResourceUtils.getFile(this.getClass().getResource("/some_file.txt"));
Paramesh Korrakuti
źródło
14

Mam projekt Maven3 przy użyciu JUnit 4.12 i Java8. Aby uzyskać ścieżkę do pliku o nazwie myxml.xmlunder src/test/resources, robię to z poziomu przypadku testowego:

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

Testowane na Ubuntu 14.04 z IntelliJ IDE. Odnośnik tutaj .

Antony
źródło
11

Cała zawartość src/test/resourcesjest kopiowana do target/test-classesfolderu. Aby pobrać plik z zasobów testowych podczas kompilacji maven, musisz załadować go z test-classesfolderu, w ten sposób:

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

Awaria:

  1. getClass().getProtectionDomain().getCodeSource().getLocation().toURI()- dam ci URI do target/test-classes.
  2. resolve(Paths.get("somefile"))- rozwiązuje someFiledo target/test-classesfolderu.

Oryginalna odpowiedź pochodzi z tego

wiśnia
źródło
8

Istnieją różnice i ograniczenia w opcjach oferowanych przez @Steve C i @ ashosborne1. Uważam, że należy je sprecyzować.

Kiedy możemy użyć File resourcesDirectory = new File("src/test/resources");:?

  • 1 Kiedy testy będą przeprowadzane tylko przez maven, ale nie przez IDE.
  • 2.1 Kiedy testy będą przeprowadzane przez maven lub
  • 2.2 poprzez IDE i tylko jeden projekt jest importowany do IDE. (Używam terminu „zaimportowany”, ponieważ jest on używany w IntelliJ IDEA. Myślę, że użytkownicy Eclipse również importują swój projekt maven). To zadziała, ponieważ katalog roboczy po uruchomieniu testów przez IDE jest taki sam jak twój projekt.
  • 3.1 Kiedy testy będą przeprowadzane przez maven lub
  • 3.2 poprzez IDE, a więcej niż jeden projekt jest importowany do IDE (gdy nie jesteś studentem, zwykle importujesz kilka projektów) ORAZ przed uruchomieniem testów przez IDE ręcznie konfigurujesz katalog roboczy dla swoich testów. Ten katalog roboczy powinien odnosić się do importowanego projektu zawierającego testy. Domyślnie katalog roboczy wszystkich projektów importowanych do IDE jest tylko jeden. Prawdopodobnie jest to ograniczenie IntelliJ IDEAtylko, ale myślę, że wszystkie IDE działają w ten sposób. Ta konfiguracja, którą należy wykonać ręcznie, wcale nie jest dobra. Praca z kilkoma testami istniejącymi w różnych projektach maven, ale zaimportowana do jednego dużego projektu „IDE”, zmusza nas do zapamiętania tego i nie pozwala się zrelaksować i czerpać przyjemność z pracy.

Rozwiązanie oferowane przez @ ashosborne1 (osobiście wolę ten) wymaga 2 dodatkowych wymagań, które należy spełnić przed uruchomieniem testów. Oto lista kroków, aby użyć tego rozwiązania:

  • Utwórz folder testowy („teva”) i plik („readme”) w „src / test / resources /”:

    src / test / resources / teva / readme

    Plik musi zostać utworzony w folderze testowym, w przeciwnym razie nie będzie działać. Maven ignoruje puste foldery.

  • Przynajmniej raz buduj projekt przez mvn clean install. Przeprowadzi również testy. Może wystarczyć uruchomienie tylko klasy testowej / metody przez maven bez budowania całego projektu. W rezultacie Twoje zasoby testowe zostaną skopiowane do klas testowych, oto ścieżka:target/test-classes/teva/readme

  • Następnie możesz uzyskać dostęp do folderu za pomocą kodu, który jest już oferowany przez @ ashosborne1 (przepraszam, że nie mogłem poprawnie edytować tego kodu na tej liście elementów):

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

Teraz możesz uruchomić test za pomocą IDE tyle razy, ile chcesz. Dopóki nie uruchomisz mvn clean. Opuści folder docelowy.

Aby utworzyć plik w folderze testowym i uruchomić maven po raz pierwszy, przed uruchomieniem testów za pomocą IDE potrzebne są kroki. Bez tych kroków, jeśli tylko w swoim IDE utworzysz zasoby testowe, a następnie napisz test i uruchom go tylko za pomocą IDE, pojawi się błąd. Uruchamianie testów za pośrednictwem mvn kopiuje zasoby testowe do target / test-klas / teva / readme i stają się one dostępne dla modułu ładującego klasy.

Możesz zapytać, dlaczego potrzebuję importować więcej niż jeden projekt maven do IDE i dlaczego tak wiele skomplikowanych rzeczy? Dla mnie jedna z głównych motywacji: trzymanie plików związanych z IDA z dala od kodu. Najpierw tworzę nowy projekt w moim IDE. To fałszywy projekt, który jest po prostu posiadaczem plików związanych z IDE. Następnie importuję już istniejące projekty maven. Zmuszam te importowane projekty do przechowywania plików IDEA tylko w moim oryginalnym fałszywym projekcie. W rezultacie nie widzę plików związanych z IDE wśród kodu. SVN nie powinien ich widzieć (proszę nie oferować konfiguracji svn / git do ignorowania takich plików, proszę). Jest to również bardzo wygodne.

Alexandr
źródło
Cześć Alexandr, mam problem z plikiem Resource w target / klas i src / main / resource i wydajesz się, że tylko o tym mówisz. Najpierw mam pliki na src / main / resource, po skompilowaniu projektu kopiuje te pliki do targetu / klas. Z tego, getClass (). GetClassLoader (). GetResource (nazwa_pliku) działa tylko na folderze docelowym, a ja chcę pracować na src / main. Czy możesz podać mi gdzieś link wyjaśniający mechanizm pliku getResource? jak skonfigurować folder zasobów? Tks: D
Huy Hóm Hỉnh
2
@Huy Hóm Hỉnh, polecam nie rób tego. Obawiam się, że poszedłeś w złym kierunku. Są pewne miejsca, w których znajdują się pliki zasobów, miejsca te znane są wszystkim innym. Łatwiejsze utrzymanie takich projektów. Nawet dla ciebie będzie łatwiej, wystarczy zrozumieć strukturę projektów maven. Ale na pewno możesz skonfigurować domyślną lokalizację zasobów za pomocą [ maven.apache.org/plugins/maven-resources-plugin/examples/…
Alexandr
@ HuyHómHỉnh, spójrz także na rozwiązanie tutaj: stackoverflow.com/questions/23289098/... Ale aby skonfigurować src / main jako zasób ... Spróbuj tego uniknąć, wygląda na to, że robisz coś złego.
Alexandr
hm. Czy mógłbyś wyjaśnić, co jest nie tak .gitignore? Wygląda również na to, że IDEA uruchamia Maven automatycznie podczas uruchamiania testów (i domyślnie ustawia prawidłowy katalog pracy $MODULE_DIR$). Nie trzeba więc wcześniej uruchamiać mvn testręcznie, wszystko działa poprawnie zarówno z Maven, jak i IDEA "src/test/resources/somefile.txt".
Alex P.
5

Najprostsze i czyste rozwiązanie, z którego korzystam, załóżmy, że nazwa klasy testowej to TestQuery1i resourceskatalog zawiera testfolder w następujący sposób:

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

Aby uzyskać identyfikator URI TestQuery1do:

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

Aby uzyskać identyfikator URI jednego z plików TestQuery1, wykonaj:

File exampleDir = new File(currentTestResourceFolder.toURI());
URI queryJSONFileURI = exampleDir.toURI().resolve("query.json");
Noor
źródło
1
Bez obaw, w rzeczywistości dziękuję za pomoc !! Dobrą rzeczą jest to, że usuwając twoją odpowiedź, mogę usunąć pytanie. Tak, tutaj też jestem bardzo sfrustrowany, ale i tak dzięki !! Dobry wieczór :)
Noor
1

Nie można używać pliku z folderu zasobów do testów w typowym przypadku. Powodem jest to, że pliki zasobów w folderze zasobów są przechowywane w słoiku. Więc nie mają prawdziwej ścieżki w systemie plików.

Najprostszym rozwiązaniem może być:

  1. Skopiuj plik z zasobów do folderu tymczasowego i uzyskaj ścieżkę do tego pliku tymczasowego.
  2. Wykonuj testy przy użyciu tymczasowej ścieżki.
  3. Usuń plik tymczasowy.

TemporaryFolderfrom JUnitmoże służyć do tworzenia plików tymczasowych i usuwania ich po zakończeniu testu. Klasy z guavabiblioteki służą do kopiowania folderu zasobów formularza pliku.

Zauważ, że jeśli użyjemy podfolderu w folderze zasobów, takiego jak goodjeden, nie musimy dodawać prowadzącego /do ścieżki zasobów.

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
źródło
0

Wykonaj następujące czynności, aby wstrzyknąć Hibernację ze sprężyną do testów jednostkowych:

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

Jeśli nie masz hibernate.cfg.xmlprezentu w src/test/resourcesfolderze, automatycznie wróci do src/main/resourcesfolderu w folderze.

białybrow
źródło
0

Użyj .getAbsolutePath () na swoim obiekcie File.

getClass().getResource("somefile").getFile().getAbsolutePath()
GreatDantone
źródło
getFile return Instancja ciągu nie FIle
Almas Abdrazak
@AlmasAbdrazak GreatDantone nie twierdzi, że getFile()zwraca instancję pliku. Mówi, że getAbsolutePath()jest używany w instancji obiektu File.
menteith
@menteith Zgodnie ze swoim kodem wywołuje getFile (), a następnie getAbsolutePath () na getFile (), ale getFile () zwraca String i nie można wywołać getAbsolutePath () na obiekcie String
Almas Abdrazak
0

Dzięki Spring możesz łatwo odczytać go z folderu zasobów (main / resources lub test / resources):

Na przykład utwórz plik: 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
źródło
0
List<String> lines = Files.readAllLines(Paths.get("src/test/resources/foo.txt"));
lines.forEach(System.out::println);
zhuguowei
źródło