Пример таргетинга на приложение

Эта категория инструментальных тестов мало чем отличается от тестов, предназначенных для обычных приложений для Android. Стоит отметить, что тестовое приложение, включающее инструментарий, должно быть подписано тем же сертификатом, что и целевое приложение.

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

В этом руководстве в качестве примера используется следующий тест:

  • frameworks/base/packages/Shell/tests

Рекомендуем сначала просмотреть код, чтобы получить общее представление о нем.

Выберите исходное местоположение

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

Дополнительную информацию о местоположении источника можно найти в примере сквозного тестирования с самостоятельной регистрацией.

Файл манифеста

Как и обычное приложение, каждый модуль инструментального тестирования должен иметь файл манифеста. Если вы назовете файл AndroidManifest.xml и разместите его рядом с файлом Android.mk для тестового модуля, он будет автоматически включен в основной файл makefile BUILD_PACKAGE.

Прежде чем продолжить, рекомендуем ознакомиться с обзором манифеста приложения.

В этом разделе описаны основные компоненты файла манифеста и их функции.

Последняя версия файла манифеста для примера изменения Gerrit доступна по адресу: https://android.googlesource.com/platform/frameworks/base/+/android17-release/packages/Shell/tests/AndroidManifest.xml.

Для удобства ниже приведен снимок экрана.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.shell.tests">

    <application>
        <uses-library android:name="android.test.runner" />

        <activity
            android:name="com.android.shell.ActionSendMultipleConsumerActivity"
            android:label="ActionSendMultipleConsumer"
            android:theme="@android:style/Theme.NoDisplay"
            android:noHistory="true"
            android:excludeFromRecents="true">
            <intent-filter>
                <action android:name="android.intent.action.SEND_MULTIPLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="*/*" />
            </intent-filter>
        </activity>
    </application>

    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
        android:targetPackage="com.android.shell"
        android:label="Tests for Shell" />

</manifest>

Некоторые примечания к файлу манифеста:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.shell.tests">

Атрибут package – это название пакета приложения для Android. Это уникальный идентификатор, который фреймворк Android использует для идентификации приложения (в данном случае – вашего тестового приложения). Каждый пользователь в системе может установить только одно приложение с таким названием пакета.

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

Кроме того, этот атрибут package возвращает те же данные, что и ComponentName#getPackageName(), и используется для взаимодействия с различными подкомандами pm через adb shell.

Обратите внимание, что хотя название пакета обычно имеет тот же стиль, что и название пакета Java, на самом деле они имеют очень мало общего. Другими словами, пакет приложения (или теста) может содержать классы с любыми названиями пакетов, но вы можете упростить себе задачу и сделать так, чтобы название пакета Java верхнего уровня в приложении или тесте совпадало с названием пакета приложения.

<uses-library android:name="android.test.runner" />

Это необходимо для всех инструментальных тестов, поскольку связанные классы упакованы в отдельный файл библиотеки JAR, поэтому при вызове пакета тестов фреймворком приложения требуются дополнительные записи в пути к классам.

android:targetPackage="com.android.shell"

В результате целевым пакетом инструментария станет com.android.shell. Когда инструмент вызывается с помощью команды am instrument, фреймворк перезапускает процесс com.android.shell и внедряет в него код инструмента для выполнения теста. Это также означает, что тестовый код будет иметь доступ ко всем экземплярам классов, работающим в тестируемом приложении, и может манипулировать состоянием в зависимости от предоставленных тестовых точек.

Простой файл конфигурации

Каждый новый тестовый модуль должен иметь файл конфигурации, чтобы направлять систему сборки с метаданными модуля, зависимостями времени компиляции и инструкциями по упаковке. В большинстве случаев достаточно варианта с файлом Blueprint на основе Soong. Подробнее о простой конфигурации тестирования…

Сложный файл конфигурации

Для более сложных тестов также необходимо написать файл конфигурации теста для тестовой программы Android Trade Federation.

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

Последнюю версию файла конфигурации для образца изменения Gerrit можно найти по адресу: frameworks/base/packages/Shell/tests/AndroidTest.xml.

Ниже приведен снимок экрана для удобства:

<configuration description="Runs Tests for Shell.">
    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
        <option name="test-file-name" value="ShellTests.apk" />
    </target_preparer>

    <option name="test-suite-tag" value="apct" />
    <option name="test-tag" value="ShellTests" />
    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
        <option name="package" value="com.android.shell.tests" />
        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
    </test>
</configuration>

Некоторые примечания к файлу конфигурации теста:

<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
  <option name="test-file-name" value="ShellTests.apk"/>
</target_preparer>

Эта команда указывает Trade Federation установить ShellTests.apk на целевое устройство с помощью указанного целевого подготовителя. В Trade Federation разработчикам доступно множество подготовителей целей, которые можно использовать, чтобы убедиться, что устройство правильно настроено перед выполнением теста.

<test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="com.android.shell.tests"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

Здесь указывается класс тестирования Trade Federation, который будет использоваться для выполнения теста, а также передаются пакеты на устройство для выполнения и фреймворк для запуска тестов, в данном случае JUnit.

Подробнее о конфигурациях тестовых модулей…

Функции JUnit4

Использование библиотеки android-support-test в качестве средства запуска тестов позволяет внедрять новые тестовые классы в стиле JUnit4, а пример изменения gerrit содержит некоторые базовые варианты использования ее функций.

Последнюю версию исходного кода для образца изменения Gerrit можно найти по следующему адресу: frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java

Хотя шаблоны тестирования обычно специфичны для команд компонентов, существуют некоторые общеполезные шаблоны использования.

@SmallTest
@RunWith(AndroidJUnit4.class)
public final class FeatureFactoryImplTest {

Важное отличие JUnit4 заключается в том, что тестам больше не нужно наследовать общий базовый класс. Вместо этого вы пишете тесты в обычных классах Java и используете аннотации, чтобы указать определенные настройки и ограничения. В этом примере мы указываем, что класс должен быть запущен как тест JUnit4 для Android.

Аннотация @SmallTest задает размер теста для всего класса. Все методы тестирования, добавленные в этот класс, наследуют аннотацию размера теста. Настройка перед классом тестирования, завершение после тестирования и завершение после класса тестирования: аналогично методам setUp и tearDown в JUnit4. Аннотация Test используется для аннотирования самого теста.

    @Before
    public void setup() {
    ...
    @Test
    public void testGetProvider_shouldCacheProvider() {
    ...

Аннотация @Before используется в методах JUnit4 для предварительной настройки перед тестированием. В этом примере не используется тег @After, который предназначен для удаления данных после тестирования. Аналогично, аннотации @BeforeClass и @AfterClass могут использоваться в методах JUnit4 для выполнения настройки перед запуском всех тестов в тестовом классе и последующего удаления. Обратите внимание, что методы настройки и очистки на уровне класса должны быть статическими.

Что касается методов тестирования, то в отличие от более ранних версий JUnit, их названия больше не должны начинаться с test. Вместо этого каждый из них должен быть аннотирован с помощью @Test. Как обычно, методы тестирования должны быть общедоступными, не возвращать значений, не принимать параметров и могут вызывать исключения.

        Context context = InstrumentationRegistry.getTargetContext();

Поскольку для тестов JUnit4 больше не требуется общий базовый класс, нет необходимости получать экземпляры Context через getContext() или getTargetContext() через методы базового класса. Вместо этого новый запускатель тестов управляет ими через InstrumentationRegistry, где хранится контекстная и экологическая настройка, созданная фреймворком для инструментов. Также в рамках этого курса можно звонить:

  • getInstrumentation() – экземпляр класса Instrumentation.
  • getArguments() – аргументы командной строки, переданные в am instrument через -e <key> <value>.

Создание и тестирование на локальном компьютере

Для большинства распространенных вариантов использования используйте Atest.

Для более сложных случаев, требующих более глубокой настройки, следуйте инструкциям по реализации.