Google is committed to advancing racial equity for Black communities. See how.
Эта страница была переведа с помощью Cloud Translation API.
Switch to English

Пример самоинструментальных тестов

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

Это означает, что инструментальный тест не может внедриться в платформу Android, также известную как системный сервер, для выполнения. Чтобы протестировать платформу Android, тестовый код может вызывать только общедоступные поверхности API или те, которые предоставляются через язык определения интерфейса Android AIDL, доступный в дереве исходного кода платформы. Для этой категории тестов не имеет смысла ориентироваться на какой-либо конкретный пакет. Поэтому обычно такие инструменты объявляются для целевого пакета тестового приложения, как определено в его собственном <manifest> AndroidManifest.xml .

В зависимости от требований пакеты тестовых приложений этой категории также могут:

  • Объедините действия, необходимые для тестирования.
  • Поделитесь идентификатором пользователя с системой.
  • Будьте подписаны с помощью ключа платформы.
  • Компилировать с исходным кодом платформы, а не с общедоступным SDK.

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

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

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

Выбор местоположения источника

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

Предполагая, что корневой каталог для вашего источника компонента находится в <component source root> , большинство компонентов имеют папки src и tests под ним, а также некоторые дополнительные файлы, такие как Android.mk (или разбиты на дополнительные файлы .mk ), файл манифеста AndroidManifest.xml и файл конфигурации теста «AndroidTest.xml».

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

В некоторых случаях ваша команда может иметь дополнительные структуры каталогов при tests из-за необходимости упаковать различные наборы тестов в отдельные файлы apks. И в этом случае вам нужно создать новый подкаталог для tests .

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

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

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

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

Это дает обзор основных компонентов файла манифеста и их функций. См. Пример по адресу platform_testing / tests / example / Instrumentation / AndroidManifest.xml .

Снимок включен сюда для удобства:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />

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

    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                     android:targetPackage="android.test.example.helloworld"
                     android:label="Hello World Test"/>

</manifest>

Некоторые избранные примечания к файлу манифеста:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

Атрибут package - это имя пакета приложения: это уникальный идентификатор, который платформа приложений Android использует для идентификации приложения (или в этом контексте: вашего тестового приложения). Каждый пользователь в системе может установить только одно приложение с этим именем пакета.

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

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

android:sharedUserId="android.uid.system"

Это означает, что во время установки этому apk должен быть предоставлен тот же идентификатор пользователя, т. Е. Идентификатор времени выполнения, что и базовой платформе. Обратите внимание, что это зависит от того, что apk подписан тем же сертификатом, что и основная платформа (см. LOCAL_CERTIFICATE в разделе выше), но это разные концепции:

  • некоторые разрешения или API защищены подписью, что требует того же сертификата подписи
  • для некоторых разрешений или API требуется system пользовательский идентификатор вызывающего, который требует, чтобы вызывающий пакет делился идентификатором пользователя с system , если это отдельный пакет от самой базовой платформы
<uses-library android:name="android.test.runner" />

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

android:targetPackage="android.test.example.helloworld"

Вы могли заметить, что targetPackage здесь объявлен так же, как атрибут package объявленный в теге manifest этого файла. Как упоминалось в разделе «Основы тестирования» , эта категория инструментальных тестов обычно предназначена для тестирования API-интерфейсов фреймворка, поэтому для них не имеет большого смысла иметь конкретный целевой пакет приложения, кроме самого себя.

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

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

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

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

Конфигурация теста может указывать специальные параметры настройки устройства и аргументы по умолчанию для предоставления тестового класса. См. Пример по адресу /platform_testing/tests/example/instrumentation/AndroidTest.xml .

Снимок включен сюда для удобства:

<configuration description="Runs sample instrumentation test.">
  <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
  <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    <option name="test-file-name" value="HelloWorldTests.apk"/>
  </target_preparer>
  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
  <option name="test-suite-tag" value="apct"/>
  <option name="test-tag" value="SampleInstrumentationTest"/>

  <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    <option name="package" value="android.test.example.helloworld"/>
    <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="HelloWorldTests.apk"/>
</target_preparer>

Это указывает Trade Federation установить HelloWorldTests.apk на целевое устройство, используя указанный target_preparer. Разработчикам в Торговой федерации доступно множество средств подготовки целевых приложений, которые можно использовать для обеспечения правильной настройки устройства перед выполнением теста.

<test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="android.test.example.helloworld"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

Он определяет тестовый класс Trade Federation, который будет использоваться для выполнения теста, и передает пакет на устройство, которое будет выполнено, и среду выполнения тестов, которой в данном случае является JUnit.

Для получения дополнительной информации см. Конфигурации тестового модуля .

Возможности JUnit4

Использование библиотеки android-support-test качестве средства запуска тестов позволяет адаптировать новые тестовые классы в стиле JUnit4, а пример изменения gerrit содержит некоторые очень простые способы использования его функций. См. Пример по адресу /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java .

Хотя шаблоны тестирования обычно специфичны для команд компонентов, есть несколько обычно полезных шаблонов использования.

@RunWith(JUnit4.class)
public class HelloWorldTest {

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

    @BeforeClass
    public static void beforeClass() {
    ...
    @AfterClass
    public static void afterClass() {
    ...
    @Before
    public void before() {
    ...
    @After
    public void after() {
    ...
    @Test
    @SmallTest
    public void testHelloWorld() {
    ...

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

Важно : сами методы тестирования аннотируются аннотацией @Test ; и обратите внимание, что для выполнения тестов через APCT они должны быть аннотированы с размерами тестов: пример аннотированного метода testHelloWorld как @SmallTest . Аннотация может применяться в области действия метода или класса.

Доступ к instrumentation

Хотя это и не рассматривается в базовом примере hello world, для Android-теста довольно часто требуется доступ к экземпляру Instrumentation : это основной интерфейс API, который обеспечивает доступ к контекстам приложения, API-интерфейсам тестирования, связанным с жизненным циклом активности, и многому другому.

Поскольку для тестов JUnit4 больше не требуется общий базовый класс, больше нет необходимости получать экземпляр Instrumentation через InstrumentationTestCase#getInstrumentation() , вместо этого новый исполнитель тестов управляет им через InstrumentationRegistry где хранятся контекстные и средовые настройки, созданные с помощью инструментария.

Чтобы получить доступ к экземпляру класса Instrumentation , просто вызовите статический метод getInstrumentation() в классе InstrumentationRegistry :

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

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

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

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