Làm thế nào để có được đường dẫn của thư mục src / test / resource trong JUnit?


275

Tôi biết tôi có thể tải một tệp từ src / test / resource với:

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

Nhưng làm thế nào tôi có thể lấy đường dẫn đầy đủ đến src / kiểm tra / nguồn thư mục , nghĩa là tôi không muốn tải một tập tin, tôi chỉ muốn biết đường dẫn của thư mục?


1
Vì tò mò: tại sao bạn muốn biết?
fge

3
@fge cần truyền nó cho đối tượng đang thử nghiệm, sử dụng nó để tải tệp
Rory

5
Truy cập tệp trực tiếp vào thư mục tài nguyên của bạn là một ý tưởng tồi. Tái cấu trúc mã của bạn để hoạt động trên hơi nước hoặc yêu cầu thử nghiệm của bạn tạo một bản sao trong Tạm thời trước.
Oliver Charlesworth

4
@OliverCharlesworth Tôi đồng ý về các thư mục tạm thời và sử dụng org.junit.rules.TemporaryFoldermọi lúc ... nhưng ... để sao chép từ bài kiểm tra / tài nguyên bạn cần biết, er, đường dẫn của nó!
mike gặm nhấm

1
@mikerodent - điều tôi nghĩ có nghĩa là: đọc tài nguyên thông qua một dòng đầu vào, sau đó ghi nó vào một tệp tạm thời.
Oliver Charlesworth

Câu trả lời:


204

Hãy thử làm việc với ClassLoaderlớp:

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

A ClassLoaderchịu trách nhiệm tải trong các lớp. Mỗi lớp có một tài liệu tham khảo đến a ClassLoader. Mã này trả về một Filetừ thư mục tài nguyên. Gọi getAbsolutePath()vào nó trả lại tuyệt đối của nó Path.

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


34
Đây không hẳn là một ý tưởng tốt. Nếu tài nguyên ở trong một Jar, điều này sẽ dẫn đến những lúc buồn.
Oliver Charlesworth

1
@OliverCharlesworth Vậy, có thể làm gì trong trường hợp bình?
Anmol Singh Jaggi

@AnmolSinghJaggi - Xem bình luận của tôi bên dưới câu hỏi ban đầu :)
Oliver Charlesworth

maven build thất bại khi tôi sử dụng giải pháp này
Firstpostcommenter

Nó cũng sẽ có tên tệp
qwert_ukg

299

Bạn không cần phải lộn xộn với trình nạp lớp. Trong thực tế, đó là một thói quen xấu để tham gia vì tài nguyên trình nạp lớp không phải là các đối tượng java.io.File khi chúng ở trong kho lưu trữ jar.

Maven tự động đặt thư mục làm việc hiện tại trước khi chạy thử nghiệm, vì vậy bạn chỉ có thể sử dụng:

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

resourcesDirectory.getAbsolutePath() sẽ trả về giá trị chính xác nếu đó là những gì bạn thực sự cần.

Tôi khuyên bạn nên tạo một src/test/datathư mục nếu bạn muốn các bài kiểm tra của mình truy cập dữ liệu qua hệ thống tệp. Điều này cho thấy rõ những gì bạn đang làm.


4
Tệp mới ("src / test / resource / fileXYZ"); sẽ không làm việc. Không phải từ Eclipse cũng như từ Maven nếu bạn chỉ đơn giản đưa nó vào một bài kiểm tra JUnit.
seba.wagner 8/12/2015

11
Nó hoạt động tốt từ Maven. Trong nhật thực, bạn sẽ cần phải thiết lập thư mục làm việc hiện tại trong trình chạy thử, nhưng dòng lệnh maven thực hiện điều này cho bạn.
Steve C

4
Tôi không nghĩ vậy. Và tại sao bạn lại làm điều đó nếu bạn có thể làm một cách đơn giản là "Tệp mới (getClass (). GetClassLoader (). GetResource (" fileNameXYZ.xml ")" mà không cần thiết lập bất cứ điều gì. Cả trong Eclipse và trong Maven.
seba .wagner

10
Thay vào đó, tại sao bạn không tuân theo các tiêu chuẩn của tiện ích xây dựng của bạn? Đặc biệt là khi nó đơn giản hóa mã của bạn. Sử dụng IntelliJ hoặc Maven, không cần thiết lập thư mục làm việc. Đây rõ ràng là giải pháp đơn giản nhất, với Eclipse luôn là một nỗi đau.
James Watkins

2
Đối với phiên bản IntelliJ 2014, tôi vẫn phải thay đổi thư mục làm việc trong các cấu hình Run / Debug của phương thức / lớp thử nghiệm, như @Steve C đã đề cập.
a_secenthusiast

76

Tôi chỉ đơn giản là sử dụng Pathtừ Java 7

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

Gọn gàng và sạch sẽ!


Mã chính xác này có hoạt động trên Windows không? JavaDoc cho Paths.get(...)gợi ý (với tôi dù thế nào đi nữa) rằng nó sẽ không.
Steve C

@SteveC bạn có thể sử dụng File.separatorhằng số để xây dựng chuỗi được sử dụng làm đường dẫn
JeanValjean

1
Tôi biết điều đó, nhưng nó rất xấu. Ngược lại, new File("src/test/resources")làm điều đúng trên tất cả các nền tảng.
Steve C

2
Tại sao không chỉ sử dụng Path resourceDirectory = Paths.get("src","test","resources");?
Navneeth

1
Hmm, Paths.get("src", "test", "resources")Paths.get("src/test/resources")hoạt động tốt trên Windows 10 đối với tôi. Tôi đang làm gì sai? =)
naXa

24

Nếu đó là một dự án mùa xuân, chúng ta có thể sử dụng đoạn mã dưới đây để lấy các tệp từ thư mục src / test / resource .

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

14

Tôi có một dự án Maven3 sử dụng JUnit 4.12 và Java8. Để có được đường dẫn của một tệp được gọi myxml.xmlbên dưới src/test/resources, tôi thực hiện điều này từ trong trường hợp thử nghiệm:

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

Đã thử nghiệm trên Ubuntu 14.04 với IntelliJ IDE. Tham khảo tại đây .


11

Tất cả nội dung trong src/test/resourcesđược sao chép vào target/test-classesthư mục. Vì vậy, để có được tệp từ tài nguyên kiểm tra trong quá trình xây dựng maven, bạn phải tải nó từ test-classesthư mục, như thế:

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

Phá vỡ:

  1. getClass().getProtectionDomain().getCodeSource().getLocation().toURI()- cung cấp cho bạn URI target/test-classes.
  2. resolve(Paths.get("somefile"))- giải quyết someFilevào target/test-classesthư mục.

Anwser gốc được lấy từ này


8

Có những khác biệt và ràng buộc trong các tùy chọn được cung cấp bởi @Steve C và @ ashosborne1. Họ phải được chỉ định, tôi tin.

Khi nào chúng ta có thể sử dụng : File resourcesDirectory = new File("src/test/resources");?

  • 1 Khi các bài kiểm tra sẽ chỉ được chạy qua maven nhưng không qua IDE.
  • 2.1 Khi các bài kiểm tra sẽ được chạy qua maven hoặc
  • 2.2 thông qua IDE và chỉ có một dự án được nhập vào IDE. . Điều này sẽ hoạt động, gây ra thư mục làm việc khi bạn chạy thử nghiệm thông qua IDE giống như dự án của bạn.
  • 3.1 Khi các bài kiểm tra sẽ được chạy qua maven hoặc
  • 3.2 qua IDE và hơn một dự án được nhập vào IDE (khi bạn không phải là sinh viên, bạn thường nhập một số dự án), trước khi bạn chạy thử qua IDE, bạn tự cấu hình thư mục làm việc cho các bài kiểm tra của mình. Thư mục làm việc đó nên tham khảo dự án đã nhập của bạn có chứa các bài kiểm tra. Theo mặc định, thư mục làm việc của tất cả các dự án được nhập vào IDE chỉ là một. Có lẽ đó là một hạn chế IntelliJ IDEAduy nhất, nhưng tôi nghĩ tất cả các IDE đều hoạt động như thế này. Và cấu hình này phải được thực hiện thủ công, không tốt chút nào. Làm việc với một số thử nghiệm hiện có trong các dự án maven khác nhau, nhưng được nhập vào một dự án IDE IDE lớn, buộc chúng tôi phải nhớ điều này và không cho phép thư giãn và nhận được niềm vui từ công việc của bạn.

Giải pháp được cung cấp bởi @ ashosborne1 (cá nhân tôi thích giải pháp này) yêu cầu 2 yêu cầu bổ sung phải được thực hiện trước khi bạn chạy thử nghiệm. Dưới đây là danh sách các bước để sử dụng giải pháp này:

  • Tạo một thư mục kiểm tra (Nhật ký trực tuyến) và tệp (Dịch vụ đọc trực tiếp) bên trong của src / test / resource / Lần:

    src / kiểm tra / tài nguyên / teva / readme

    Tập tin phải được tạo trong thư mục thử nghiệm, nếu không, nó sẽ không hoạt động. Maven bỏ qua các thư mục trống.

  • Ít nhất một lần xây dựng dự án thông qua mvn clean install. Nó cũng sẽ chạy thử nghiệm. Nó có thể là đủ để chỉ chạy lớp / phương thức thử nghiệm của bạn thông qua maven mà không xây dựng toàn bộ dự án. Kết quả là tài nguyên kiểm tra của bạn sẽ được sao chép vào các lớp kiểm tra, đây là một đường dẫn:target/test-classes/teva/readme
  • Sau đó, bạn có thể truy cập thư mục bằng mã, đã được cung cấp bởi @ ashosborne1 (Tôi xin lỗi, tôi không thể chỉnh sửa mã này trong danh sách các mục này một cách chính xác):
public static final String TEVA_FOLDER = "teva"; ... 
URL tevaUrl = YourTest.class.getClassLoader().getResource(TEVA_FOLDER); 
String tevaTestFolder = new File(tevaUrl.toURI()).getAbsolutePath();

Bây giờ bạn có thể chạy thử nghiệm của mình thông qua IDE nhiều lần bạn muốn. Cho đến khi bạn chạy mvn sạch. Nó sẽ thả thư mục đích.

Tạo tệp trong thư mục kiểm tra và chạy maven lần đầu tiên, trước khi bạn chạy kiểm tra qua IDE là các bước cần thiết. Nếu không có các bước này, nếu bạn chỉ trong IDE tạo tài nguyên kiểm tra, sau đó viết kiểm tra và chỉ chạy qua IDE, bạn sẽ gặp lỗi. Chạy thử nghiệm thông qua mvn sao chép tài nguyên kiểm tra vào mục tiêu / lớp kiểm tra / teva / readme và chúng có thể truy cập được đối với trình nạp lớp.

Bạn có thể hỏi, tại sao tôi cần nhập nhiều hơn một dự án maven trong IDE và tại sao có quá nhiều thứ phức tạp? Đối với tôi, một trong những động lực chính: giữ các tệp liên quan đến IDA cách xa mã. Trước tiên tôi tạo một dự án mới trong IDE của mình. Đây là một dự án giả mạo, đó chỉ là một người giữ các tệp liên quan đến IDE. Sau đó, tôi nhập các dự án maven hiện có. Tôi buộc các dự án đã nhập này chỉ giữ các tệp IDEA trong dự án giả mạo ban đầu của mình. Kết quả là tôi không thấy các tệp liên quan đến IDE trong số các mã. SVN không nên nhìn thấy chúng (vui lòng không cấu hình svn / git để bỏ qua các tệp như vậy). Ngoài ra nó chỉ là rất thuận tiện.


Xin chào Alexandr, tôi đang gặp rắc rối với tệp Tài nguyên trong mục tiêu / lớp và src / main / resource và bạn dường như là người duy nhất nói về nó. Đầu tiên tôi có các tệp trên src / main / resource, sau khi xây dựng dự án, nó sao chép các tệp này vào đích / lớp. Và từ đây, getClass (). GetClassLoader (). GetResource (fileName) chỉ hoạt động trên thư mục đích trong khi tôi muốn tôi làm việc trên src / main. Bạn có thể cho tôi liên kết ở đâu đó giải thích về cơ chế của tệp getResource không? Làm thế nào để cấu hình thư mục tài nguyên? Tks: D
Huy Hóm Hành

2
@Huy Hóm Hóm, tôi khuyên bạn không nên làm điều đó. Tôi e rằng bạn đi sai hướng. Có những nơi nhất định nơi đặt các tệp tài nguyên, những nơi được biết đến cho tất cả các nơi khác. Dễ dàng hơn để duy trì các dự án như vậy. Ngay cả đối với bạn nó sẽ dễ dàng hơn, bạn chỉ cần hiểu cấu trúc của các dự án maven. Nhưng chắc chắn, bạn có thể định cấu hình vị trí tài nguyên mặc định với [ maven.apache.org/plugins/maven-resource-plugin/examples/ Lỗi
Alexandr

@ HuyHómHật, Cũng có một cái nhìn về giải pháp ở đây: stackoverflow.com/questions/23289098/ Nhưng Nhưng để cấu hình bạn src / main làm tài nguyên ... Hãy cố gắng tránh nó, có vẻ như bạn đã làm gì đó sai.
Alexandr

hm Bạn có thể giải thích những gì sai với .gitignore? Ngoài ra, có vẻ như IDEA chạy Maven tự động khi chạy thử nghiệm (và đặt thư mục làm việc chính xác theo mặc định, $MODULE_DIR$). Vì vậy, không cần phải chạy mvn testthủ công trước đó, mọi thứ đều hoạt động tốt từ cả Maven và IDEA "src/test/resources/somefile.txt".
Alex P.

5

Giải pháp đơn giản và gọn gàng nhất mà tôi sử dụng, giả sử tên của lớp kiểm tra là TestQuery1và có một resourcesthư testmục trong thư mục của bạn như sau:

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

Để lấy URI của TestQuery1:

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

Để lấy URI của một trong các tệp TestQuery1, hãy làm:

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

1
Đừng lo lắng, thực tế cảm ơn sự giúp đỡ của bạn !! Điều tốt là xóa câu trả lời của bạn, tôi có thể xóa câu hỏi. Vâng, khá thất vọng ở đây cũng có, nhưng dù sao cũng cảm ơn !! Chào buổi tối :)
Noor

1

Bạn không thể sử dụng tệp từ thư mục tài nguyên để kiểm tra trong trường hợp phổ biến. Lý do là các tệp tài nguyên trong thư mục tài nguyên được lưu trữ bên trong một tệp jar. Vì vậy, họ không có một đường dẫn thực sự trong hệ thống tập tin.

Giải pháp đơn giản nhất có thể là:

  1. Sao chép một tệp từ tài nguyên vào thư mục tạm thời và nhận đường dẫn đến tệp tạm thời đó.
  2. Làm các xét nghiệm bằng cách sử dụng một đường dẫn tạm thời.
  3. Xóa tập tin tạm thời.

TemporaryFoldertừ JUnitcó thể được sử dụng để tạo tập tin tạm thời và xóa nó sau khi thử nghiệm được khen. Các lớp từ guavathư viện được sử dụng để sao chép một thư mục tài nguyên mẫu tệp.

Xin lưu ý rằng nếu chúng ta sử dụng thư mục con trong thư mục tài nguyên, như thư mục con good, chúng ta không phải thêm dẫn /đến đường dẫn tài nguyên.

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

Sử dụng cách sau để tiêm Hibernate với Spring trong bài kiểm tra đơn vị của bạn:

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

Nếu bạn không có hibernate.cfg.xmlquà trong src/test/resourcesthư mục của mình, nó sẽ tự động rơi trở lại vào src/main/resourcesthư mục của bạn .


0

Sử dụng .getAbsolutePath () trên đối tượng Tệp của bạn.

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

Ví dụ chuỗi trả về getFile không FIle
Almas Abdrazak

@AlmasAbdrazak GreatDantone không nói rằng getFile()trả về một thể hiện của tệp. Ông nói rằng nó getAbsolutePath()được sử dụng trên một thể hiện của đối tượng File.
Menteith

@menteith Theo mã của anh ấy, anh ấy gọi getFile () và sau đó getAbsolutePath () trên getFile () nhưng getFile () trả về String và bạn không thể gọi getAbsolutePath () trên đối tượng String
Almas Abdrazak

0

Với Spring, bạn có thể dễ dàng đọc nó từ thư mục tài nguyên (chính / tài nguyên hoặc kiểm tra / tài nguyên):

Ví dụ: tạo một tệp: 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;
}

0
List<String> lines = Files.readAllLines(Paths.get("src/test/resources/foo.txt"));
lines.forEach(System.out::println);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.