Блок тестування Android Studio: зчитування файлу даних (вхідних даних)


96

В одиничному тесті, як я можу прочитати дані з файлу json у моїй (настільній) файловій системі, без жорсткого кодування шляху?

Я хотів би прочитати тестові дані (для моїх методів синтаксичного аналізу) із файлу, а не створювати статичні рядки.

Файл знаходиться в тому самому місці, що і мій код модульного тестування, але я також можу розмістити його десь ще в проекті, якщо це потрібно. Я використовую Android Studio.


3
Я спробував майже кожну комбінацію з IOUtils.toString (this.getClass (). GetResourceAsStream ("test_documents.json"), "UTF-8"), вона завжди повертає null. Можливо тому, що файли не будуть включені в банку.
Френк

Ми говоримо про модульні тести за участю емулятора / пристрою Android?
AndroidEx

@ Android777 Я думаю, ми говоримо про нову підтримку модульних тестів, представлену в останній версії інструментів Android Studio. Android.com/tech-docs/unit-testing-support
akhy

@Frank, де ти розміщуєшся test_documents.json? каталог активів?
akhy

Так, ми говоримо про нову підтримку модульного тесту, не залучаючи емулятор / пристрій. Я не помістив його в папку активів, оскільки тоді він упаковується разом із активним apk. Я помістив його в ту ж папку, що і тестові (java) файли.
Френк

Відповіді:


149

Залежно від android-gradle-pluginверсії:

1. версія 1.5 і вище:

Просто помістіть файл json src/test/resources/test.jsonі посилайтеся на нього як

classLoader.getResource("test.json"). 

Ніяких модифікацій градле не потрібно.

2. версія нижче 1.5 : (або якщо з якихось причин вищевказане рішення не працює)

  1. Переконайтеся, що ви використовуєте принаймні плагін Android Gradle версії 1.1 . Перейдіть за посиланням, щоб правильно налаштувати Android Studio.

  2. Створити testкаталог. Помістіть класи модульних тестів у javaкаталог і помістіть файл ресурсів у resкаталог. Android Studio має позначити їх як такі:

    введіть тут опис зображення

  3. Створити gradleзавдання для копіювання ресурсів у каталог класів, щоб зробити їх видимими для classloader:

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
  4. Тепер ви можете використовувати цей метод, щоб отримати Fileпосилання на файловий ресурс:

    private static File getFileFromPath(Object obj, String fileName) {
        ClassLoader classLoader = obj.getClass().getClassLoader();
        URL resource = classLoader.getResource(fileName);
        return new File(resource.getPath());
    }
    
    @Test
    public void fileObjectShouldNotBeNull() throws Exception {
        File file = getFileFromPath(this, "res/test.json");
        assertThat(file, notNullValue());
    }
  5. Запустіть одиничний тест за допомогою Ctrl+ Shift+ F10для всього класу або специфічного методу тестування.

1
Дивовижно! Ваша редакція, без інструментальних тестів, працює як шарм, дякую!
Френк

4
Це гарне рішення, але воно працює не завжди. Якщо ви виконуєте чисте завдання, а потім запускаєте testDebug, це не вдається. В основному розробник повинен знати, що він повинен запустити завдання assembleDebug перед testDebug. Ви, хлопці, маєте пропозицію покращити це?
joaoprudencio

18
З AndroidStudio 1.5 з андроїд-плагіном 1.5.0 розмістіть тут свій json-файл src/test/resources/test.jsonі позначте його як classLoader.getResource("test.json"). Ніяких модифікацій градле не потрібно. Вкладені папки всередині resourcesтакож працюють.
Сергій Печенізький

6
Неповна відповідь. Що таке classLoader? де розмістити цей рядок коду? що ви можете зробити з результатом повернення ?. Будь ласка, надайте більш повний код. -1
voghDev

3
Читати ./src/test/resources/file.txtв Котліні:TestClassName::class.java.getResource("/file.txt")!!.readText()
Ерік,

76

Для локальних модульних тестів (порівняно з контрольно-вимірювальними приладами) ви можете помістити файли src/test/resourcesта прочитати їх за допомогою classLoader. Наприклад, наступний код відкриває myFile.txtфайл у каталозі ресурсів.

InputStream in = this.getClass().getClassLoader().getResourceAsStream("myFile.txt");

Це працювало з

  • Android Studio 1.5.1
  • плагін gradle 1.3.1

Це не працює для мене, будь ласка, перегляньте моє запитання тут stackoverflow.com/questions/36295824/…
Тайлер Пфафф,

5
Це спрацювало для мене, коли я перейшов із "src / test / res" на "src / test / resources". Використання Android Studio 2.0 RC 3, gradle: 2.0.0-rc3
Алекс Браво,

працював, як очікувалося. Але тест отримує пропуск, навіть якщо файл не доступний у "src / test / resources /", наприклад: "rules.xml", але в цьому випадку результати InputStream є нульовими.
ананд криш

4
kotlin:val myFile = ClassLoader.getSystemResource("myFile.txt").readText()
jj.

Працював як шарм!
Аміт Бхандарі,

15

У моєму випадку рішення було додати до файлу gradle

sourceSets {
    test.resources.srcDirs += 'src/unitTests/resources'
  } 

Після нього все було знайдено AS 2.3.1

javaClass.classLoader.getResourceAsStream("countries.txt")

Я зробив щось дуже подібне (Kotlin): 1. створити папку та файл за адресою: root/app/src/test/resources/test.json 2. прочитати дані на зразок цього:val jsonFile = ClassLoader.getSystemResource("test.json").readText()
jj.

8

У мене було багато проблем з тестовими ресурсами в Android Studio, тому я встановив кілька тестів для наочності. У свій проект mobile(Додаток Android) я додав такі файли:

mobile/src/test/java/test/ResourceTest.java
mobile/src/test/resources/test.txt
mobile/src/test/resources/test/samePackage.txt

Тестовий клас (всі тести проходять):

assertTrue(getClass().getResource("test.txt") == null);
assertTrue(getClass().getResource("/test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getResource("samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getResource("/test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getClassLoader().getResource("test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getClassLoader().getResource("test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));

У тому ж корені проект У мене є проект Java (НЕ Android) під назвою data. Якщо я додаю ті самі файли до проекту даних:

data/src/test/java/test/ResourceTest.java
data/src/test/resources/test.txt
data/src/test/resources/test/samePackage.txt

Тоді всі наведені вище тести не пройдуть, якщо я їх виконаю з Android Studio, але вони пройдуть у командному рядку з ./gradlew data:test. Щоб обійти це, я використовую цей хак (у Groovy)

def resource(String path) {
    getClass().getResource(path) ?:
            // Hack to load test resources when executing tests from Android Studio
            new File(getClass().getClassLoader().getResource('.').path
                    .replace('/build/classes/test/', "/build/resources/test$path"))
}

Використання: resource('/test.txt')

Android Studio 2.3, Gradle 3.3


Чудова відповідь (через 45 хвилин пошуку 😌). Це потрапляє в суть кількох питань і дозволяє легко відтворити результати за допомогою самих тестів. Fwiw, В AS 2.3.1, Gradle 2.3.1, getClassLoader()версії працюють належним чином . Тобто вони знаходять файли, які запускаються з Android Studio І з командного рядка на моїй машині macOS, і на сервері Linux CI (CircleCI). Тож я піду з цим і сподіваюся, що Gradle 3.3 цього не зламає пізніше ...
mm2001

Приємно! Я бачу ту саму проблему завантаження ресурсів тут. AS 2.3.2, Gradle 3.3. Тести працюють із командного рядка, але не через AS, через те, що вони build/resources/testне включені в інтерактивний шлях до класу.
Марк Маккенна,

6

Якщо ви перейдете до Виконати -> Редагувати конфігурації -> JUnit, а потім вибрати конфігурацію запуску для своїх модульних тестів, буде встановлено параметр "Робочий каталог". Це повинно вказувати на те, де б не знаходився ваш json-файл. Майте на увазі, це може призвести до розриву інших тестів.


а чим використовувати this.getClass (). getResourceAsStream (test.json)? Я додав файли туди, у кореневій частині проекту, він все ще не знаходить файли.
Френк

Це може бути використано для завантаження файлів за допомогою new File()або подібного, але це не працює безпосередньо з методом завантаження classpath, описаним вище. Це також трохи хитро, тому що кожна нова конфігурація запуску повинна встановлювати робочий каталог, і за замовчуванням AS та Gradle командний рядок люблять використовувати різні робочі каталоги ... такий біль
Марк Маккенна,

4

Хоча мені слід додати тут свої висновки. Я знаю, що це трохи старе, але для новіших версій Gradle, де немає каталогу src / test / resources, а лише один єдиний каталог ресурсів для всього проекту, вам потрібно додати цей рядок у файл Gradle.

android {
   testOptions {
      unitTests {
         includeAndroidResources = true
      }
    }
}

Завдяки цьому ви можете отримати доступ до свого ресурсу за допомогою:

 this.getClass().getClassLoader().getResourceAsStream(fileName);

Я шукав це і не міг знайти відповіді, тому вирішив допомогти іншим тут.


1

Власне, це те, що працювало у мене з інструментарними тестами (Запуск Android Studio версії 3.5.3 , Плагін Android Gradle версії 3.5.3 , Gradle версії 6.0.1 ):

  1. Помістіть свої файли src/androidTest/assets папку
  2. У вашому тестовому файлі:

InputStream is = InstrumentationRegistry.getInstrumentation().getContext().getAssets().open("filename.txt");

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.