วิธีรับพา ธ ของไดเร็กทอรี src / test / resources ใน JUnit?


275

ฉันรู้ว่าฉันสามารถโหลดไฟล์จาก src / test / resources ด้วย:

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

แต่ฉันจะหาเส้นทางแบบเต็มไปยังไดเรกทอรี src / test / resources ได้อย่างไรเช่นฉันไม่ต้องการโหลดไฟล์ฉันแค่อยากรู้เส้นทางของไดเรกทอรี


1
จากความอยากรู้: ทำไมคุณถึงอยากรู้?
fge

3
จำเป็น @fge จะผ่านมันไปยังวัตถุภายใต้การทดสอบซึ่งใช้มันในการโหลดไฟล์
Rory

5
การเข้าถึงไฟล์โดยตรงไปยังไดเรกทอรีทรัพยากรของคุณเป็นความคิดที่ไม่ดี refactor รหัสของคุณเพื่อทำงานบนไอน้ำหรือให้การทดสอบของคุณสร้างสำเนาในโฟลเดอร์ชั่วคราวก่อน
Oliver Charlesworth

4
@OliverCharlesworth ฉันเห็นด้วยเกี่ยวกับโฟลเดอร์ temp และใช้org.junit.rules.TemporaryFolderตลอดเวลา ... แต่ ... เพื่อคัดลอกจากการทดสอบ / ทรัพยากรที่คุณต้องรู้เอ้อเส้นทางของมัน!
mike rodent

1
@mikerodent - สิ่งที่ฉันคิดว่าหมายถึงคือ: อ่านทรัพยากรผ่านทางอินพุตสตรีมแล้วเขียนลงในไฟล์ชั่วคราว
Oliver Charlesworth

คำตอบ:


204

ลองทำงานกับClassLoaderชั้นเรียน:

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

A ClassLoaderรับผิดชอบในการโหลดในชั้นเรียน ClassLoaderทุกชั้นมีการอ้างอิงถึง รหัสนี้ส่งคืน a Fileจากไดเรกทอรีทรัพยากร โทรได้ที่จะส่งกลับแน่นอนgetAbsolutePath()Path

Javadoc สำหรับClassLoader: http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html


34
นี่ไม่ใช่ความคิดที่ดี หากทรัพยากรอยู่ใน Jar สิ่งนี้จะนำไปสู่ช่วงเวลาที่น่าเศร้า
Oliver Charlesworth

1
@OliverCharlesworth ดังนั้นสิ่งที่สามารถทำได้ในกรณีของขวด?
Anmol Singh Jaggi

@AnmolSinghJaggi - ดูความคิดเห็นของฉันด้านล่างคำถามเดิม :)
Oliver Charlesworth

การสร้าง maven ล้มเหลวเมื่อฉันใช้วิธีนี้
firstpostcommenter

มันจะอยู่กับชื่อไฟล์ด้วย
qwert_ukg

299

คุณไม่จำเป็นต้องยุ่งกับรถตักของห้องเรียน ในความเป็นจริงมันเป็นนิสัยที่ไม่ดีที่จะเข้าไปเพราะทรัพยากรตัวโหลดคลาสไม่ใช่ java.io.File ออบเจ็กต์เมื่ออยู่ในไฟล์เก็บถาวร jar

Maven จะตั้งค่าไดเรกทอรีการทำงานปัจจุบันโดยอัตโนมัติก่อนทำการทดสอบดังนั้นคุณสามารถใช้:

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

resourcesDirectory.getAbsolutePath() จะคืนค่าที่ถูกต้องหากนั่นคือสิ่งที่คุณต้องการจริงๆ

ฉันขอแนะนำให้สร้างsrc/test/dataไดเรกทอรีหากคุณต้องการให้การทดสอบของคุณเข้าถึงข้อมูลผ่านระบบไฟล์ สิ่งนี้ทำให้ชัดเจนว่าคุณกำลังทำอะไร


4
แฟ้มใหม่ ("src / test / resources / fileXYZ"); จะไม่ทำงาน. ไม่ว่าจะมาจาก Eclipse หรือจาก Maven หากคุณเพียงแค่ทดสอบ JUnit
seba.wagner

11
มันใช้งานได้ดีจาก Maven ใน eclipse คุณจะต้องตั้งไดเรกทอรีการทำงานปัจจุบันใน test runner แต่ maven บรรทัดคำสั่งจะทำสิ่งนี้ให้คุณ
Steve C

4
ฉันไม่คิดอย่างนั้น และทำไมคุณถึงทำเช่นนั้นถ้าคุณสามารถทำได้เพียง "ไฟล์ใหม่ (getClass (). getClassLoader (). getResource (" fileNameXYZ.xml ")" โดยไม่จำเป็นต้องตั้งค่าใด ๆ ทั้งใน Eclipse หรือใน Maven
seba .wagner

10
แต่ทำไมคุณไม่ทำตามมาตรฐานของยูทิลิตี้บิลด์? โดยเฉพาะอย่างยิ่งเมื่อมันทำให้รหัสของคุณง่ายขึ้น การใช้ IntelliJ หรือ Maven ไม่จำเป็นต้องตั้งค่าไดเรกทอรีทำงาน เห็นได้ชัดว่านี่เป็นทางออกที่ง่ายที่สุดโดย Eclipse เป็นความเจ็บปวดเช่นเคย
James Watkins

2
สำหรับเวอร์ชั่น IntelliJ 2014 ฉันยังคงต้องเปลี่ยนไดเรกทอรีการทำงานในการกำหนดค่า Run / Debug ของวิธีการทดสอบ / คลาสตามที่ @Steve C กล่าวถึง
a_secenthusiast

76

ฉันจะใช้Pathจาก Java 7

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

เรียบร้อยและสะอาด!


รหัสเดียวกันนี้จะใช้ได้กับ Windows หรือไม่ JavaDoc สำหรับการPaths.get(...)แนะนำ (สำหรับฉันอยู่แล้ว) ว่ามันจะไม่
Steve C

@SteveC คุณสามารถใช้File.separatorค่าคงที่เพื่อสร้างสตริงที่จะใช้เป็นเส้นทางได้
JeanValjean

1
ฉันรู้ว่า แต่มันน่าเกลียดมาก ในทางตรงกันข้ามnew File("src/test/resources")สิ่งที่ถูกต้องในทุกแพลตฟอร์ม
Steve C

2
ทำไมไม่ใช้เพียงPath resourceDirectory = Paths.get("src","test","resources");?
Navneeth

1
อืมPaths.get("src", "test", "resources")และPaths.get("src/test/resources")ทำงานได้ดีบน Windows 10 สำหรับฉัน ผมทำอะไรผิดหรือเปล่า? =)
naXa

24

ถ้ามันเป็นโครงการฤดูใบไม้ผลิที่เราสามารถใช้รหัสที่อยู่ด้านล่างที่จะได้รับไฟล์จากsrc / test / ทรัพยากรโฟลเดอร์

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

14

ฉันมีโครงการ Maven3 ที่ใช้ JUnit 4.12 และ Java8 เพื่อให้ได้เส้นทางของไฟล์ชื่อmyxml.xmlภายใต้src/test/resourcesฉันทำสิ่งนี้จากในกรณีทดสอบ:

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

ทดสอบบน Ubuntu 14.04 ด้วย IntelliJ IDE อ้างอิงที่นี่


11

เนื้อหาทั้งหมดในsrc/test/resourcesจะถูกคัดลอกไปยังtarget/test-classesโฟลเดอร์ ดังนั้นในการรับไฟล์จากแหล่งข้อมูลทดสอบในระหว่างการสร้าง Maven คุณจะต้องโหลดจากtest-classesโฟลเดอร์เช่น:

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

ทำให้พังถล่ม:

  1. getClass().getProtectionDomain().getCodeSource().getLocation().toURI()- ให้ URI แก่target/test-classesคุณ
  2. resolve(Paths.get("somefile"))- แก้ไขsomeFileเป็นtarget/test-classesโฟลเดอร์

Anwser ดั้งเดิมนำมาจากสิ่งนี้


8

มีความแตกต่างและข้อ จำกัด ในตัวเลือกที่เสนอโดย @Steve C และ @ ashosborne1 พวกเขาต้องระบุฉันเชื่อ

เมื่อเราสามารถสามารถใช้: File resourcesDirectory = new File("src/test/resources");?

  • 1 เมื่อการทดสอบจะถูกเรียกใช้ผ่าน maven เท่านั้น แต่ไม่ผ่าน IDE
  • 2.1 เมื่อการทดสอบจะถูกเรียกใช้ผ่านทาง Maven หรือ
  • 2.2 ผ่าน IDE และมีเพียงโครงการเดียวที่นำเข้าสู่ IDE (ฉันใช้คำว่า "นำเข้า" ทำให้ใช้ใน IntelliJ IDEA ฉันคิดว่าผู้ใช้ eclipse ยังนำเข้าโครงการ maven ด้วย) สิ่งนี้จะใช้งานได้ทำให้ไดเรกทอรีทำงานเมื่อคุณเรียกใช้การทดสอบผ่าน IDE จะเหมือนกับโครงการของคุณ
  • 3.1 เมื่อการทดสอบจะถูกเรียกใช้ผ่านทาง Maven หรือ
  • 3.2 ผ่าน IDE และมีการนำเข้ามากกว่าหนึ่งโครงการใน IDE (เมื่อคุณไม่ใช่นักเรียนคุณมักจะนำเข้าหลายโครงการ) และก่อนที่คุณจะรันการทดสอบผ่าน IDE คุณจะกำหนดไดเรกทอรีทำงานสำหรับการทดสอบของคุณด้วยตนเอง ไดเรกทอรีการทำงานนั้นควรอ้างถึงโครงการนำเข้าของคุณที่มีการทดสอบ โดยค่าเริ่มต้นไดเรกทอรีการทำงานของโครงการทั้งหมดที่นำเข้าสู่ IDE เป็นเพียงโครงการเดียว อาจเป็นข้อ จำกัดIntelliJ IDEAเพียงอย่างเดียว แต่ฉันคิดว่า IDE ทั้งหมดทำงานเช่นนี้ และการกำหนดค่าที่ต้องทำด้วยตนเองนี้ไม่ดีเลย การทำงานกับการทดสอบหลายอย่างที่มีอยู่ในโครงการ maven ที่แตกต่างกัน แต่นำเข้าสู่โครงการ "IDE" ขนาดใหญ่หนึ่งโครงการบังคับให้เราจดจำสิ่งนี้และไม่อนุญาตให้ผ่อนคลายและเพลิดเพลินกับงานของคุณ

โซลูชันที่เสนอโดย @ ashosborne1 (โดยส่วนตัวแล้วฉันชอบสิ่งนี้) ต้องมีข้อกำหนดเพิ่มเติม 2 ข้อที่ต้องทำก่อนที่คุณจะทำการทดสอบ นี่คือรายการของขั้นตอนในการใช้วิธีแก้ไขปัญหานี้:

  • สร้างโฟลเดอร์ทดสอบ (“ teva”) และไฟล์ (“ readme”) ภายใน“ src / test / resources /”:

    src / test / ทรัพยากร / Teva / README

    ไฟล์จะต้องสร้างขึ้นในโฟลเดอร์ทดสอบมิฉะนั้นจะไม่สามารถใช้งานได้ Maven ไม่สนใจโฟลเดอร์ว่าง

  • mvn clean installอย่างน้อยหนึ่งครั้งสร้างโครงการผ่านทาง มันจะทำการทดสอบด้วย อาจจะเพียงพอที่จะรันเฉพาะคลาสการทดสอบ / วิธีการของคุณผ่าน maven โดยไม่ต้องสร้างโครงการทั้งหมด เป็นผลให้ทรัพยากรการทดสอบของคุณจะถูกคัดลอกลงในคลาสทดสอบนี่คือเส้นทาง:target/test-classes/teva/readme

  • หลังจากนั้นคุณสามารถเข้าถึงโฟลเดอร์โดยใช้รหัสที่เสนอโดย @ ashosborne1 (ขออภัยด้วยที่ฉันไม่สามารถแก้ไขรหัสนี้ภายในรายการได้อย่างถูกต้อง):

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

ตอนนี้คุณสามารถรันการทดสอบผ่าน IDE หลาย ๆ ครั้งตามที่คุณต้องการ จนกว่าคุณจะเรียกใช้ mvn สะอาด มันจะวางโฟลเดอร์เป้าหมาย

การสร้างไฟล์ภายในโฟลเดอร์ทดสอบและเรียกใช้ maven เป็นครั้งแรกก่อนที่คุณจะรันการทดสอบผ่าน IDE เป็นขั้นตอนที่จำเป็น หากไม่มีขั้นตอนเหล่านี้หากคุณเพียงแค่สร้าง IDE ในแหล่งข้อมูลการทดสอบจากนั้นให้เขียนการทดสอบและเรียกใช้ผ่าน IDE เท่านั้นคุณจะพบข้อผิดพลาด การรันการทดสอบผ่าน mvn จะคัดลอกทรัพยากรการทดสอบไปยังเป้าหมาย / test-classes / teva / readme และพวกเขาสามารถเข้าถึงได้สำหรับ classloader

คุณอาจถามว่าทำไมฉันต้องนำเข้ามากกว่าหนึ่งโครงการ Maven ใน IDE และทำไมสิ่งที่ซับซ้อนมาก? สำหรับฉันแล้วหนึ่งในแรงจูงใจหลักคือการรักษาไฟล์ที่เกี่ยวข้องกับ IDA ให้ห่างจากโค้ด ฉันก่อนสร้างโครงการใหม่ใน IDE ของฉัน มันเป็นโครงการปลอมที่เป็นเพียงผู้ถือแฟ้มที่เกี่ยวข้องกับ IDE จากนั้นฉันก็นำเข้าโครงการ maven ที่มีอยู่แล้ว ฉันบังคับให้โครงการที่นำเข้าเหล่านี้เก็บไฟล์ IDEA ในโครงการปลอมต้นฉบับของฉันเท่านั้น ดังนั้นฉันไม่เห็นไฟล์ที่เกี่ยวข้องกับ IDE ระหว่างรหัส SVN ไม่ควรเห็นพวกเขา (ไม่เสนอให้กำหนดค่า svn / git ให้ละเว้นไฟล์ดังกล่าวโปรด) นอกจากนี้ยังสะดวกสบายมาก


สวัสดี Alexandr ฉันมีปัญหากับไฟล์ Resource ในเป้าหมาย / คลาสและ src / main / resource และดูเหมือนว่าคุณจะพูดถึงมันคนเดียว ก่อนอื่นฉันมีไฟล์ใน src / main / resource หลังจาก build project มันก็อปปี้ไฟล์เหล่านี้ไปยังเป้าหมาย / คลาส และจากนี้ getClass (). getClassLoader (). getResource (fileName) ใช้งานได้กับโฟลเดอร์เป้าหมายเท่านั้นในขณะที่ฉันต้องการทำงานกับ src / main คุณสามารถให้ลิงค์กับฉันอธิบายเกี่ยวกับกลไกของไฟล์ getResource ได้ไหม? วิธีกำหนดค่าโฟลเดอร์ทรัพยากร Tks: D
Huy HómHỉnh

2
@Huy HómHỉnhฉันอยากจะแนะนำอย่าทำมัน ฉันเกรงว่าคุณจะไปในทิศทางที่ผิดมีบางสถานที่ที่ไฟล์ทรัพยากรตั้งอยู่สถานที่เป็นที่รู้จักกันทั้งหมด ง่ายต่อการบำรุงรักษาโครงการดังกล่าว แม้สำหรับคุณมันจะง่ายขึ้นคุณเพียงแค่ต้องเข้าใจโครงสร้างของโครงการ Maven แต่แน่นอนคุณสามารถกำหนดค่าตำแหน่งทรัพยากรเริ่มต้นด้วย [ maven.apache.org/plugins/maven-resources-plugin/examples/ …
Alexandr

@ HuyHómHỉnhดูวิธีแก้ปัญหาได้ที่นี่: stackoverflow.com/questions/23289098// แต่การกำหนดค่า src / main เป็นทรัพยากร ... พยายามหลีกเลี่ยงดูเหมือนว่าคุณทำอะไรผิดไป
Alexandr

ฮึ่ม คุณช่วยอธิบายสิ่งที่ผิดกับ.gitignoreไหม? นอกจากนี้ดูเหมือนว่า IDEA จะรัน Maven โดยอัตโนมัติเมื่อทำการทดสอบ (และตั้งค่า dir ที่ใช้งานได้ตามค่าเริ่มต้น$MODULE_DIR$) ดังนั้นจึงไม่มีความจำเป็นที่จะต้องทำงานด้วยตนเองก่อนที่ทุกอย่างทำงานได้ดีทั้งจากผู้เชี่ยวชาญและความคิดที่มีเพียงmvn test "src/test/resources/somefile.txt"
Alex P.

5

ทางออกที่ง่ายและสะอาดที่สุดที่ฉันใช้สมมติว่าชื่อของคลาสทดสอบคือTestQuery1และมีresourcesไดเรกทอรีในtestโฟลเดอร์ของคุณดังนี้:

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

ในการรับ URI TestQuery1สิ่งที่ต้องทำ:

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

ในการรับ URI ของไฟล์ใดไฟล์หนึ่งTestQuery1ให้ทำ:

File exampleDir = new File(currentTestResourceFolder.toURI());
URI queryJSONFileURI = exampleDir.toURI().resolve("query.json");

1
ไม่ต้องกังวลจริงๆแล้วขอบคุณสำหรับความช่วยเหลือของคุณ !! สิ่งที่ดีคือการลบคำตอบของคุณฉันสามารถลบคำถามได้ ใช่ค่อนข้างผิดหวังจากที่นี่เช่นกัน แต่ก็ต้องขอบคุณ !! ดีตอนเย็น :)
นูร์

1

คุณไม่สามารถใช้ไฟล์จากโฟลเดอร์ทรัพยากรสำหรับการทดสอบในกรณีทั่วไป เหตุผลคือไฟล์ทรัพยากรในโฟลเดอร์ทรัพยากรจะถูกเก็บไว้ในขวด ดังนั้นพวกเขาจึงไม่มีเส้นทางที่แท้จริงในระบบไฟล์

ทางออกที่ง่ายที่สุดคือ:

  1. คัดลอกไฟล์จากทรัพยากรไปยังโฟลเดอร์ชั่วคราวและรับเส้นทางไปยังไฟล์ชั่วคราว
  2. ทำการทดสอบโดยใช้พา ธ ชั่วคราว
  3. ลบไฟล์ชั่วคราว

TemporaryFolderจากJUnitสามารถใช้เพื่อสร้างไฟล์ชั่วคราวและลบออกหลังจากการทดสอบถูกร้องเรียน ชั้นเรียนจากguavaไลบรารีใช้เพื่อคัดลอกโฟลเดอร์ทรัพยากรของไฟล์

โปรดสังเกตว่าถ้าเราใช้โฟลเดอร์ย่อยในโฟลเดอร์ทรัพยากรgoodเราไม่จำเป็นต้องเพิ่มผู้นำ/ในเส้นทางของทรัพยากร

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;
    }

}

0

ใช้สิ่งต่อไปนี้เพื่อฉีด Hibernate with Spring ในการทดสอบหน่วยของคุณ:

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

หากคุณไม่มีhibernate.cfg.xmlของขวัญในsrc/test/resourcesโฟลเดอร์ของคุณมันจะย้อนกลับไปที่รายการในsrc/main/resourcesโฟลเดอร์ของคุณโดยอัตโนมัติ


0

ใช้. getAbsolutePath () บนวัตถุไฟล์ของคุณ

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

getFile return เช่นสตริงไม่ใช่ FIle
Almas Abdrazak

@AlmasAbdrazak GreatDantone ไม่ได้บอกว่าgetFile()คืนค่าอินสแตนซ์ของไฟล์ เขาบอกว่าgetAbsolutePath()มันถูกใช้กับอินสแตนซ์ของวัตถุไฟล์
menteith

@menteith ตามรหัสของเขาเขาเรียก getFile () แล้ว getAbsolutePath () บน getFile () แต่ getFile () ส่งคืนสตริงและคุณไม่สามารถเรียก getAbsolutePath () บนวัตถุ String
Almas Abdrazak

0

ด้วย Spring คุณสามารถอ่านได้อย่างง่ายดายจากโฟลเดอร์ทรัพยากร (หลัก / ทรัพยากรหรือทดสอบ / ทรัพยากร):

ตัวอย่างเช่นสร้างไฟล์: 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;
}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.