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

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

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

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

  • фреймворки/база/пакеты/оболочка/тесты

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

Определите местоположение источника

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

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

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

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

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

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

Последнюю версию файла манифеста для примера изменения gerrit можно получить по адресу: https://android.googlesource.com/platform/frameworks/base/+/android16-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 использует для идентификации приложения (или, в данном контексте, вашего тестового приложения). Каждый пользователь в системе может установить только одно приложение с этим именем пакета.

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

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

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

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

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

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 на целевое устройство с помощью указанного препаратора target_preparer. Разработчикам Trade Federation доступно множество препараторов target, которые можно использовать для правильной настройки устройства перед выполнением теста.

<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 и используются аннотации для указания определённых настроек и ограничений теста. В этом примере мы указываем, что этот класс должен запускаться как тест Android JUnit4.

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

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

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

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

        Context context = InstrumentationRegistry.getTargetContext();

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

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

Сборка и тестирование локально

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

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