Как получить путь к каталогу src / test / resources в JUnit?

275

Я знаю, что могу загрузить файл из src / test / resources с помощью:

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

Но как я могу получить полный путь к SRC / тест / ресурсы каталога , то есть я не хочу , чтобы загрузить файл, я просто хочу знать путь каталога?

Рори
источник
1
Из любопытства: почему ты хочешь знать?
2015 года
3
@fge нужно передать его тестируемому объекту, который использует его для загрузки файла
Рори,
5
Прямой доступ к файлу в вашем каталоге ресурсов - плохая идея. Рефакторинг вашего кода для работы на steam или пусть ваш тест сначала создаст копию в TemporaryFolder.
Оливер Чарльзуорт
4
@OliverCharlesworth Я согласен с временными папками и использую их org.junit.rules.TemporaryFolderвсе время ... но ... чтобы скопировать из test / resources, вам нужно знать его путь!
Майк Грызун
1
@mikerodent - я думаю, что имел в виду: прочитать ресурс с помощью inputsream, а затем записать его во временный файл.
Оливер Чарльзуорт

Ответы:

204

Попробуйте поработать с ClassLoaderклассом:

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

ClassLoaderОтвечает за загрузку в классах. Каждый класс имеет ссылку на ClassLoader. Этот код возвращает Fileиз каталога ресурсов. Обращение getAbsolutePath()к нему возвращает его абсолют Path.

Javadoc для ClassLoader: http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html

ashosborne1
источник
35
Это не обязательно хорошая идея. Если ресурс находится в банке, это приведет к печальным временам.
Оливер Чарльзуорт
1
@OliverCharlesworth Итак, что можно сделать в случае банки?
Анмол Сингх Джагги
@AnmolSinghJaggi - Смотрите мой комментарий ниже оригинального вопроса :)
Оливер
сборка 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 вам нужно будет установить текущий рабочий каталог в тестовом средстве, но командная строка maven сделает это за вас.
Стив C
4
Я так не думаю. И зачем вам это делать, если вы можете сделать просто «новый файл (getClass (). GetClassLoader (). GetResource (« fileNameXYZ.xml »)» без необходимости что-либо настраивать. Ни в Eclipse, ни в Maven.
seba .wagner
10
Скорее, почему бы вам не следовать стандартам вашей утилиты сборки? Особенно, когда это упрощает ваш код. Используя IntelliJ или Maven, нет необходимости устанавливать рабочий каталог. Это, очевидно, самое простое решение, так как Eclipse - это боль, как всегда.
Джеймс Уоткинс
2
Для версии IntelliJ 2014 мне все равно пришлось изменить рабочий каталог в конфигурациях Run / Debug тестового метода / класса, как упоминалось в @Steve C.
a_secenthusiast
76

Я бы просто использовал Pathиз Java 7

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

С иголочки!

Жан Вальжан
источник
Будет ли этот точно такой же код работать в Windows? JavaDoc для Paths.get(...)предполагает (для меня в любом случае), что это не будет.
Стив C
@SteveC вы можете использовать File.separatorконстанту для построения строки, которая будет использоваться в качестве пути
JeanValjean
1
Я знаю это, но это очень некрасиво. Напротив, new File("src/test/resources")делает правильные вещи на всех платформах.
Стив C
2
Почему бы просто не использовать Path resourceDirectory = Paths.get("src","test","resources");?
Навнит
1
Хм, Paths.get("src", "test", "resources")и Paths.get("src/test/resources")отлично работает на Windows 10 для меня. Что я делаю не так? =)
naXa
24

Если это весенний проект, мы можем использовать приведенный ниже код для получения файлов из папки src / test / resource .

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. Ссылка здесь .

Antony
источник
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папку.

Оригинальный ответ взят из этого

вишня
источник
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 / тест / ресурсы / Teva / ридми

    Файл должен быть создан в тестовой папке, иначе он не будет работать. 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 clean. Это удалит целевую папку.

Создание файла внутри тестовой папки и запуск maven в первый раз, прежде чем запускать тесты через IDE, являются необходимыми шагами. Без этих шагов, если вы просто в своей среде IDE создаете тестовые ресурсы, а затем пишете test и запускаете его только через IDE, вы получите ошибку. Запуск тестов через mvn копирует тестовые ресурсы в target / test-classes / teva / readme, и они становятся доступными для загрузчика классов.

Вы можете спросить: зачем мне импортировать более одного проекта maven в IDE и почему так много сложных вещей? Для меня одна из главных причин: держать связанные с IDA файлы вдали от кода. Сначала я создаю новый проект в моей IDE. Это фальшивый проект, который просто содержит файлы, связанные с IDE. Затем я импортирую уже существующие проекты Maven. Я заставляю эти импортированные проекты сохранять файлы IDEA только в моем исходном поддельном проекте. В результате я не вижу связанных с IDE файлов среди кода. SVN не должен их видеть (не предлагайте настраивать svn / git, чтобы игнорировать такие файлы, пожалуйста). И это просто очень удобно.

Александр
источник
Привет, Александр, у меня проблемы с файлом ресурсов в target / classes и src / main / resource, и вы, кажется, единственный, кто говорит об этом. Сначала у меня есть файлы в src / main / resource, после сборки проекта он копирует эти файлы в target / classes. И из этого getClass (). GetClassLoader (). GetResource (fileName) работают только с целевой папкой, а я хочу работать с src / main. Можете ли вы дать мне ссылку где-нибудь объяснить механизм механизма getResource? как настроить ресурсную папку? Tks: D
Huy Hóm Hỉnh
2
@ Привет, Хм, я бы порекомендовал не делать этого. Я боюсь, что вы идете в неправильном направлении. Есть определенные места, где находятся файлы ресурсов, места известны всем остальным. Проще поддерживать такие проекты. Даже вам будет легче, вам просто нужно понять структуру maven проектов. Но наверняка вы можете настроить расположение ресурса по умолчанию с помощью [ maven.apache.org/plugins/maven-resources-plugin/examples/…
Alexandr
@ HuyHómHỉnh, также взгляните на решение здесь: stackoverflow.com/questions/23289098/… Но чтобы настроить ваш src / main как ресурс ... Попытайтесь избежать этого, похоже, вы делаете что-то не так.
Александр
гектометр Не могли бы вы уточнить, в чем дело .gitignore? Также похоже, что IDEA автоматически запускает Maven при запуске тестов (и по умолчанию устанавливает правильный рабочий каталог $MODULE_DIR$). Таким образом, нет необходимости запускать mvn testвручную до этого, все прекрасно работает как с Maven, так и с IDEA только с "src/test/resources/somefile.txt".
Алекс П.
5

Самое простое и чистое решение я использует, пусть имя тестового класса TestQuery1и есть resourcesкаталог в testпапке следующим образом :

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

Чтобы получить URI TestQuery1do:

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

Чтобы получить URI одного из файлов TestQuery1, выполните:

File exampleDir = new File(currentTestResourceFolder.toURI());
URI queryJSONFileURI = exampleDir.toURI().resolve("query.json");
Noor
источник
1
Не беспокойтесь, на самом деле спасибо за вашу помощь! Хорошо, что, удалив ваш ответ, я могу удалить вопрос. Да, здесь тоже довольно расстроено, но все равно спасибо !! Добрый вечер :)
Noor
1

Вы не можете использовать файл из папки ресурсов для тестов в общем случае. Причина в том, что файлы ресурсов в папке ресурсов хранятся в банке. Таким образом, у них нет реального пути в файловой системе.

Наиболее простым решением может быть:

  1. Скопируйте файл из ресурсов во временную папку и получите путь к этому временному файлу.
  2. Делайте тесты, используя временный путь.
  3. Удалить временный файл.

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

}
v.ladynev
источник
0

Используйте следующее, чтобы внедрить Hibernate с 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 () для вашего объекта File.

getClass().getResource("somefile").getFile().getAbsolutePath()
GreatDantone
источник
getFile возвращает строковый экземпляр, а не файл
Алмас Абдразак
@AlmasAbdrazak GreatDantone не говорит, что getFile()возвращает экземпляр файла. Он говорит, что getAbsolutePath()используется на экземпляре объекта File.
Menteith
@menteith Согласно его коду, он вызывает getFile (), а затем getAbsolutePath () для getFile (), но getFile () возвращает String, и вы не можете вызвать getAbsolutePath () для объекта String
Almas Abdrazak
0

С помощью Spring вы можете легко прочитать его из папки ресурсов (либо main / resources, либо test / resources):

Например, создайте файл: 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
источник
0
List<String> lines = Files.readAllLines(Paths.get("src/test/resources/foo.txt"));
lines.forEach(System.out::println);
zhuguowei
источник