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

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

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

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

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

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

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

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

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

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

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

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

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

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

android:targetPackage="com.android.shell"

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

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

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

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

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

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

Последнюю версию файла конфигурации для примера изменения геррита можно получить по адресу: 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 доступно множество средств подготовки целевых объектов, которые можно использовать для обеспечения правильной настройки устройства перед выполнением теста.

<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 содержит некоторые базовые возможности использования ее функций.

Последний исходный код примера изменения геррита доступен по адресу: 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 для выполнения настройки перед выполнением всех тестов в тестовом классе и последующего удаления. Обратите внимание, что методы установки и удаления области класса должны быть статическими.

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

        Context context = InstrumentationRegistry.getTargetContext();

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

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

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

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

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