Как читать тестовый файл в Android unit test

Для моего приложения для Android я пишу модульные тесты, требующие чтения некоторых файлов. Поскольку это тестовые файлы, я не хочу их в своих папках res, так как я не хочу, чтобы они попали в мой последний файл .apk.

Я хочу сделать что-то похожее на этот вопрос, но используя недавно добавленный (в Gradle 1.1) unit test поддержка (в отличие от контрольно-измерительного теста).

Моя структура проекта выглядит следующим образом:

/app
   /src
      /main
         /java/my.module/myClass.java
         /res/production_resources_go_here
      /test
         /java/my.module/myClassTest.java
         /resources/testFile.txt

Что должен мой тест myClassTest выглядеть так, чтобы иметь возможность успешно читать testFile.txt?

Ответ 1

В то время, когда этот вопрос задавался, это просто не работало. К счастью, это было исправлено с тех пор.

Вы должны поместить свой текстовый файл в папку app/src/test/resources, которую пытался выполнить OP. Кроме того, он должен быть в том же пакете, что и ваш тестовый класс. Поэтому, если у вас есть ReadFileTest.java в пакете com.example.test в папке app/src/test/java, тогда ваш тестовый файл должен быть в app/src/test/resources/com/example/test.

тестовая структура папок

Затем вы можете перейти к текстовому файлу следующим образом:

getClass().getResourceAsStream("testFile.txt")

Это открывает текстовый файл InputStream. Если вы не знаете, что с ним делать, вот некоторые из его способов: Чтение/преобразование InputStream в строку

Ответ 2

Добавьте это в свой build.gradle:

android {
    sourceSets {
        test {
           resources.srcDirs += ['src/test/resources']
        }
        androidTest {
           resources.srcDirs += ['src/androidTest/resources']
        }
    }
}

Чтобы ресурсы были доступны для модульных тестов, добавьте свои файлы в: src/test/resources. И для контрольных тестов добавьте свои файлы в: src/androidTest/resources.

Ответ 3

Я работаю над проектом со структурой, подобной той, о которой вы говорили. Я поместил все ответы своего сервера в файл в папке resources, например app/src/test/resources/BookingInfo.json.

Все тестовые файлы java находятся под app/src/test/java/PACKAGE_NAME, аналогично тому, что вы сказали. У меня есть класс Fixture под пакетом, который содержит имя ресурсов:

@SuppressWarnings("nls")
public final class Fixtures
{
    public static final String GET_ANNOUNCEMENT = "GetAnnouncement.json";
...
}

И, наконец, класс FixtureUtils, который метод этого класса отвечает за чтение файла ресурсов и возврат результата.

import java.nio.file.Files;
import java.nio.file.Paths;

public class FixtureUtils
    {
        public static final AFixture fixtureFromName(final String fixtureName)
        {
            final String fixtureString = FixtureUtils.stringFromAsset(fixtureName);

            if (StringUtils.isEmpty(fixtureString))
            {
                return null;
            }

            final Gson gson = new Gson();
            final AFixture aFixture = gson.fromJson(fixtureString, AFixture.class);
            return aFixture;
        }

        private static final String stringFromAsset(final String filename)
        {
            try
            {
                final URL resourceURL = ClassLoader.getSystemResource(filename);
                if (resourceURL == null)
                {
                    return null;
                }

                final String result = new String(Files.readAllBytes(Paths.get(resourceURL.toURI())),
                                Charset.forName("UTF-8")); //$NON-NLS-1$
                return result;
            }
            catch (final Exception e)
            {
                e.printStackTrace();
            }

            return null;
        }

        private FixtureUtils()
        {
            // Ensure Singleton
        }
    }

И класс AFixture выглядит следующим образом:

public class AFixture
{
    public List<JsonElement> validItems;
    public List<JsonElement> invalidItems;

    public AFixture()
    {
        super();
    }

    public List<JsonElement> getInvalidItems()
    {
        return this.invalidItems;
    }

    public List<JsonElement> getValidItems()
    {
        return this.validItems;
    }

    public void setInvalidItems(final List<JsonElement> invalidItems)
    {
        this.invalidItems = invalidItems;
    }

    public void setValidItems(final List<JsonElement> validItems)
    {
        this.validItems = validItems;
    }

}

Примечание: java.nio.file было удалено из JDK8, если я не ошибаюсь, однако у вас нет проблем, если вы используете JDK7. Если вы используете JDK8, вам просто нужно изменить метод stringFromAsset таким образом, как FileInputStream (стиль старой моды) или сканер.

Ответ 4

После ответа @Deepansu я объединил тестовые данные в директории {project root}/sampledata, которая по умолчанию является установкой Android Studio New > Sample Data Directory.

1. В своем проекте щелкните правой кнопкой мыши и выберите New > Sample Data Directory. Это создаст каталог sampledata в app, который имеет ту же иерархию, что и файлы build.gradle, src и build.

2. В build.gradle добавьте скрипты, как показано ниже:

android {
    sourceSets {
        test {
           resources.srcDirs += ['sampledata']
        }
        androidTest {
           resources.srcDirs += ['sampledata']
        }
    }
}

3. Sync в gradle.

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

Вы можете прочитать файл, как показано ниже:

// use somewhere at test logic. Note that slash symbol is required (or not).
jsonObject = new JSONObject(readFromFile("/testFile.json"));

// a method to read text file.
public String readFromFile(String filename) throws IOException {
    InputStream is = getClass().getResourceAsStream(filename);
    StringBuilder stringBuilder = new StringBuilder();
    int i;
    byte[] b = new byte[4096];
    while ((i = is.read(b)) != -1) {
        stringBuilder.append(new String(b, 0, i));
    }
    return stringBuilder.toString();
}

Ответ 5

Примером правильного способа сделать это было бы поместить файл в папку с вашими ресурсами. Однако содержимое папки активов будет добавлено в apk.

InputStream is = resources.getAssets().open("test.txt");

Вы можете обмануть эту систему и перейти к любому другому файлу в вашем проекте. Не забудьте создать каталог ресурсов в местоположении, указанном в файле iml проекта (например, src/main/assets).

InputStream is = resources.getAssets().open("../../test/resources/testFile.txt");

Примером способа получения ресурсов будет:

Resources resources = new Activity().getResources();