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