Google стремится продвигать расовую справедливость для черных сообществ. Смотри как.
Эта страница была переведа с помощью Cloud Translation API.
Switch to English

Пример тестов с самоинструментом

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

Это означает, что инструментальный тест не может внедрить себя в платформу Android, то есть системный сервер, для выполнения. Чтобы протестировать платформу Android, тестовый код может вызывать только открытые поверхности API или те, которые доступны через AIDL языка определения интерфейса Android, доступный в дереве исходного кода платформы. Для этой категории тестов не имеет смысла ориентироваться на какой-либо конкретный пакет. Следовательно, такие инструментарии обычно объявляются для целевого пакета тестового приложения, как определено в его собственном <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 в примере изменения геррита. Разделы ниже объяснят более подробно каждый файл.

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

Как и в обычном приложении, для каждого модуля тестирования инструментов необходим файл манифеста. Если вы назовете файл AndroidManifest.xml и предоставите его рядом с Android.mk для своего тестового модуля, он будет автоматически включен в основной файл 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" />
 

Это необходимо для всех тестов Instrumentation, поскольку связанные классы упакованы в отдельный файл библиотеки 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 аннотации @BeforeClass и @AfterClass используются в методах JUnit4 для выполнения настройки перед выполнением всех тестов в классе тестирования и последующего разборки. Обратите внимание, что методы настройки и удаления класса должны быть статическими. Что касается методов тестирования, в отличие от более ранней версии JUnit, им больше не нужно начинать имя метода с test , вместо этого каждый из них должен быть аннотирован @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 .

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