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

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

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

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

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

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

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

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

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

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

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

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

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

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

android:targetPackage="com.android.shell"

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

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

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

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

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

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

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

        Context context = InstrumentationRegistry.getTargetContext();

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

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

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

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

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