Bagaimana cara mendapatkan path direktori src / test / resources di JUnit?

275

Saya tahu saya dapat memuat file dari src / test / resources dengan:

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

Tetapi bagaimana saya bisa mendapatkan path lengkap ke direktori src / test / resources , yaitu saya tidak ingin memuat file, saya hanya ingin tahu path direktori?

Rory
sumber
1
Karena penasaran: mengapa Anda ingin tahu?
fge
3
@fge perlu meneruskannya ke objek yang sedang diuji, yang menggunakannya untuk memuat file
Rory
5
Akses file langsung ke direktori sumber daya Anda adalah ide yang buruk. Refactor kode Anda untuk beroperasi pada steam, atau minta pengujian Anda membuat salinan di TemporaryFolder terlebih dahulu.
Oliver Charlesworth
4
@OliverCharlesworth Saya setuju tentang folder temp dan gunakan org.junit.rules.TemporaryFoldersepanjang waktu ... tapi ... untuk menyalin dari tes / sumber yang perlu Anda ketahui, eh, jalannya!
mike rodent
1
@mikerodent - maksud saya adalah: membaca sumber daya melalui inputstream, dan kemudian menulisnya ke file sementara.
Oliver Charlesworth

Jawaban:

204

Cobalah bekerja dengan ClassLoaderkelas:

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

A ClassLoaderbertanggung jawab untuk memuat di kelas. Setiap kelas memiliki referensi ke a ClassLoader. Kode ini mengembalikan a Filedari direktori sumber daya. Memanggilnya getAbsolutePath()mengembalikan absolutnya Path.

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

ashosborne1
sumber
34
Ini tidak selalu merupakan ide yang bagus. Jika sumber daya ada di Jar, ini akan menyebabkan masa sedih.
Oliver Charlesworth
1
@OliverCharlesworth Jadi, apa yang bisa dilakukan jika tabung?
Anmol Singh Jaggi
@AnmolSinghJaggi - Lihat komentar saya di bawah pertanyaan awal :)
Oliver Charlesworth
maven build gagal ketika saya menggunakan solusi ini
firstpostcommenter
Itu akan dengan nama file juga
qwert_ukg
299

Anda tidak perlu dipusingkan dengan pemuat kelas. Sebenarnya itu kebiasaan buruk untuk masuk karena sumber daya loader kelas bukan objek java.io.File ketika mereka berada di arsip jar.

Maven secara otomatis menetapkan direktori kerja saat ini sebelum menjalankan tes, jadi Anda bisa menggunakan:

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

resourcesDirectory.getAbsolutePath() akan mengembalikan nilai yang benar jika itu yang benar-benar Anda butuhkan.

Saya sarankan membuat src/test/datadirektori jika Anda ingin tes Anda mengakses data melalui sistem file. Ini menjelaskan apa yang Anda lakukan.

Steve C
sumber
4
File baru ("src / test / resources / fileXYZ"); tidak akan berfungsi. Baik dari Eclipse maupun dari Maven jika Anda hanya memasukkannya ke dalam tes JUnit.
seba.wagner
11
Ini bekerja dengan baik dari Maven. Dalam gerhana Anda perlu mengatur direktori kerja saat ini di test runner, tetapi baris perintah pakar melakukan ini untuk Anda.
Steve C
4
Saya kira tidak. Dan mengapa Anda melakukan itu jika Anda hanya dapat melakukan "File baru (getClass (). GetClassLoader (). GetResource (" fileNameXYZ.xml ")" tanpa perlu mengatur apa pun. Baik di Eclipse maupun di Maven.
seba .wagner
10
Sebaliknya, mengapa Anda tidak mengikuti standar utilitas bangunan Anda? Terutama ketika menyederhanakan kode Anda. Menggunakan IntelliJ atau Maven, tidak perlu mengatur direktori kerja. Ini jelas merupakan solusi yang paling sederhana, dengan Eclipse menjadi sakit seperti biasa.
James Watkins
2
Untuk versi IntelliJ 2014, saya masih harus mengubah direktori kerja dalam konfigurasi Run / Debug dari metode uji / kelas, seperti yang disebutkan @Steve C.
a_secenthusiast
76

Saya hanya akan menggunakan Pathdari Java 7

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

Rapi dan bersih!

JeanValjean
sumber
Apakah kode yang sama persis ini berfungsi pada Windows? JavaDoc untuk Paths.get(...)menyarankan (to me anyway) bahwa itu tidak akan terjadi.
Steve C
@SteveC Anda dapat menggunakan File.separatorkonstanta untuk membangun string yang akan digunakan sebagai jalur
JeanValjean
1
Saya tahu itu, tetapi sangat jelek. Sebaliknya, new File("src/test/resources")melakukan hal yang benar di semua platform.
Steve C
2
Kenapa tidak pakai saja Path resourceDirectory = Paths.get("src","test","resources");?
Navneeth
1
Hmm, Paths.get("src", "test", "resources")dan Paths.get("src/test/resources")bekerja dengan baik pada Windows 10 untuk saya. Apa yang saya lakukan salah? =)
naXa
24

Jika ini adalah proyek semi, kita dapat menggunakan kode di bawah ini untuk mendapatkan file dari folder src / test / resource .

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

Saya punya proyek Maven3 menggunakan JUnit 4.12 dan Java8. Dalam rangka untuk mendapatkan path dari file bernama myxml.xmlbawah src/test/resources, saya melakukan ini dari dalam kasus uji:

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

Diuji pada Ubuntu 14,04 dengan IntelliJ IDE. Referensi di sini .

Antony
sumber
11

Semua konten di src/test/resourcesdisalin ke target/test-classesfolder. Jadi untuk mendapatkan file dari sumber daya uji selama maven build Anda harus memuatnya dari test-classesfolder, seperti itu:

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

Kerusakan:

  1. getClass().getProtectionDomain().getCodeSource().getLocation().toURI()- memberi Anda URI untuk target/test-classes.
  2. resolve(Paths.get("somefile"))- memutuskan someFileke target/test-classesfolder.

Anwser asli diambil dari ini

ceri
sumber
8

Ada perbedaan dan kendala dalam opsi yang ditawarkan oleh @Steve C dan @ ashosborne1. Mereka harus ditentukan, saya percaya.

Kapan kita bisa menggunakan File resourcesDirectory = new File("src/test/resources");:?

  • 1 Ketika tes akan dijalankan melalui pakar saja tetapi tidak melalui IDE.
  • 2.1 Ketika tes akan dijalankan melalui pakar atau
  • 2.2 via IDE dan hanya satu proyek yang diimpor ke IDE. (Saya menggunakan istilah "diimpor", karena ini digunakan dalam IntelliJ IDEA. Saya pikir pengguna eclipse juga mengimpor proyek pakar mereka). Ini akan berfungsi, menyebabkan direktori yang berfungsi ketika Anda menjalankan tes melalui IDE sama dengan proyek Anda.
  • 3.1 Ketika tes akan dijalankan melalui pakar atau
  • 3,2 melalui IDE, dan lebih dari satu proyek diimpor ke IDE (ketika Anda bukan mahasiswa, Anda biasanya mengimpor beberapa proyek), DAN sebelum Anda menjalankan tes melalui IDE, Anda secara manual mengkonfigurasi direktori kerja untuk tes Anda. Direktori kerja itu harus merujuk ke proyek Anda yang diimpor yang berisi tes. Secara default, direktori kerja semua proyek yang diimpor ke IDE hanya satu. Mungkin itu adalah pembatasan IntelliJ IDEAsaja, tapi saya pikir semua IDE bekerja seperti ini. Dan konfigurasi ini yang harus dilakukan secara manual, tidak baik sama sekali. Bekerja dengan beberapa tes yang ada di berbagai proyek pakar, tetapi diimpor ke dalam satu proyek "IDE" besar, memaksa kami untuk mengingat ini dan tidak mengizinkan untuk bersantai dan mendapatkan kesenangan dari pekerjaan Anda.

Solusi yang ditawarkan oleh @ ashosborne1 (secara pribadi saya lebih suka yang ini) memerlukan 2 persyaratan tambahan yang harus dilakukan sebelum Anda menjalankan tes. Berikut adalah daftar langkah-langkah untuk menggunakan solusi ini:

  • Buat folder uji ("teva") dan file ("readme") di dalam "src / test / resources /":

    src / test / resources / teva / readme

    File harus dibuat di folder tes, jika tidak, itu tidak akan berfungsi. Maven mengabaikan folder kosong.

  • Setidaknya satu kali membangun proyek melalui mvn clean install. Ini akan menjalankan tes juga. Mungkin cukup hanya menjalankan kelas uji / metode Anda melalui pakar tanpa membangun keseluruhan proyek. Alhasil sumber daya pengujian Anda akan disalin ke kelas-kelas tes, di sini ada jalannya:target/test-classes/teva/readme

  • Setelah itu, Anda dapat mengakses folder menggunakan kode, yang sudah ditawarkan oleh @ ashosborne1 (Maaf, saya tidak dapat mengedit kode ini di dalam daftar item ini dengan benar):

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

Sekarang Anda dapat menjalankan tes Anda melalui IDE sebanyak yang Anda inginkan. Sampai Anda menjalankan mvn clean. Ini akan menjatuhkan folder target.

Membuat file di dalam folder tes dan menjalankan pakar pertama kali, sebelum Anda menjalankan tes melalui IDE diperlukan langkah-langkah. Tanpa langkah-langkah ini, jika Anda hanya di IDE membuat sumber daya pengujian, kemudian menulis tes dan menjalankannya hanya melalui IDE, Anda akan mendapatkan kesalahan. Menjalankan tes melalui mvn menyalin sumber daya pengujian ke target / kelas-tes / teva / readme dan mereka dapat diakses oleh classloader.

Anda mungkin bertanya, mengapa saya perlu mengimpor lebih dari satu proyek pakar dalam IDE dan mengapa begitu banyak hal yang rumit? Bagi saya, salah satu motivasi utama: menjaga file terkait IDA jauh dari kode. Saya pertama kali membuat proyek baru di IDE saya. Ini adalah proyek palsu, itu hanya pemegang file terkait IDE. Kemudian, saya mengimpor proyek pakar yang sudah ada. Saya memaksa proyek-proyek yang diimpor ini untuk menyimpan file IDEA hanya dalam proyek palsu asli saya. Akibatnya saya tidak melihat file terkait IDE di antara kode. SVN seharusnya tidak melihatnya (jangan menawarkan untuk mengkonfigurasi svn / git untuk mengabaikan file seperti itu, silakan). Juga sangat nyaman.

Alexandr
sumber
Halo Alexandr, saya bermasalah dengan file Resource di target / kelas dan src / main / resource dan sepertinya Anda satu-satunya yang membicarakannya. Pertama saya punya file di src / main / resource, setelah membangun proyek, salin file ini ke target / kelas. Dan dari sini, getClass (). GetClassLoader (). GetResource (fileName) hanya berfungsi pada folder target sementara saya ingin saya bekerja pada src / main. Bisakah Anda memberi saya tautan di suatu tempat yang menjelaskan tentang mekanisme file getResource? cara mengkonfigurasi folder Sumber Daya? Tks: D
Huy Hóm Hỉnh
2
@ Beli Hom Hom, saya akan merekomendasikan jangan lakukan itu. Saya khawatir Anda pergi ke arah yang salah. Ada tempat-tempat tertentu di mana file sumber daya berada, tempat-tempat yang dikenal untuk semua lainnya. Lebih mudah memelihara proyek seperti itu. Bahkan bagi Anda itu akan lebih mudah, Anda hanya perlu memahami struktur proyek pakar. Namun yang pasti, Anda dapat mengonfigurasi lokasi sumber daya default dengan [ maven.apache.org/plugins/maven-resources-plugin/examples/…
Alexandr
@ HuyHómHỉnh, Lihat juga solusinya di sini: stackoverflow.com/questions/23289098/... Tetapi untuk mengonfigurasi Anda src / main sebagai sumber daya ... Cobalah untuk menghindarinya, sepertinya Anda melakukan sesuatu yang salah.
Alexandr
hm Bisakah Anda menguraikan apa yang salah .gitignore? Sepertinya IDEA menjalankan Maven secara otomatis saat menjalankan tes (dan menetapkan dir yang berfungsi dengan benar, $MODULE_DIR$). Jadi tidak perlu dijalankan mvn testsecara manual sebelum itu, semuanya berfungsi baik dari Maven dan IDEA hanya dengan "src/test/resources/somefile.txt".
Alex P.
5

Solusi paling sederhana dan bersih yang saya gunakan, misalkan nama kelas tes adalah TestQuery1dan ada resourcesdirektori di testfolder Anda sebagai berikut:

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

Untuk mendapatkan URI dari TestQuery1lakukan:

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

Untuk mendapatkan URI dari salah satu file TestQuery1, lakukan:

File exampleDir = new File(currentTestResourceFolder.toURI());
URI queryJSONFileURI = exampleDir.toURI().resolve("query.json");
Noor
sumber
1
Jangan khawatir, sebenarnya terima kasih atas bantuan Anda !! Hal yang baik adalah menghapus jawaban Anda, saya dapat menghapus pertanyaan. Ya, cukup frustrasi di sini juga, tapi tetap terima kasih !! Selamat malam :)
Noor
1

Anda tidak dapat menggunakan file dari folder sumber daya untuk pengujian dalam kasus umum. Alasannya adalah bahwa file sumber daya dalam folder sumber daya disimpan di dalam toples. Jadi mereka tidak memiliki jalur nyata dalam sistem file.

Solusi paling sederhana adalah:

  1. Salin file dari sumber daya ke folder sementara dan dapatkan jalur ke file sementara itu.
  2. Lakukan tes menggunakan jalur sementara.
  3. Hapus file sementara.

TemporaryFolderdari JUnitdapat digunakan untuk membuat file sementara dan menghapusnya setelah pengujian selesai. Kelas dari guavaperpustakaan digunakan untuk menyalin folder sumber daya formulir file.

Tolong, perhatikan bahwa jika kita menggunakan subfolder di folder sumber daya, seperti goodsatu, kita tidak perlu menambahkan mengarah /ke jalur sumber daya.

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
sumber
0

Gunakan yang berikut ini untuk menyuntikkan Hibernate dengan Spring dalam pengujian unit Anda:

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

Jika Anda tidak memiliki hibernate.cfg.xmlhadiah di src/test/resourcesfolder Anda, itu akan secara otomatis kembali ke yang ada di src/main/resourcesfolder Anda .

whitebrow
sumber
0

Gunakan .getAbsolutePath () pada objek File Anda.

getClass().getResource("somefile").getFile().getAbsolutePath()
GreatDantone
sumber
getFile return String instance bukan FIle
Almas Abdrazak
@AlmasAbdrazak GreatDantone tidak mengatakan bahwa getFile()mengembalikan instance file. Dia mengatakan itu getAbsolutePath()digunakan pada instance objek File.
menteith
@menteith Menurut kodenya, ia memanggil getFile () dan kemudian getAbsolutePath () di getFile () tetapi getFile () mengembalikan String dan Anda tidak bisa memanggil getAbsolutePath () pada objek String
Almas Abdrazak
0

Dengan Spring Anda dapat dengan mudah membacanya dari folder sumber daya (baik utama / sumber daya atau tes / sumber daya):

Misalnya membuat file: 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
sumber
0
List<String> lines = Files.readAllLines(Paths.get("src/test/resources/foo.txt"));
lines.forEach(System.out::println);
zhuguowei
sumber