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

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

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

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

  • frameworks/base/packages/Shell/tests

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

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

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

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

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

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

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

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

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

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

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

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

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

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