Тестовое сопоставление

Это краткое введение в отображение тестов и объяснение того, как начать настраивать тесты в Android Open Source Project (AOSP).

О тестовом картировании

Тестовое отображение — это подход на основе Gerrit, который позволяет разработчикам создавать правила тестирования presubmit и postsubmit непосредственно в исходном дереве Android и оставлять решения о ветвях и устройствах для тестирования тестовой инфраструктуре. Определения тестового отображения — это файлы JSON с именем TEST_MAPPING , которые можно разместить в любом исходном каталоге.

Atest может использовать файлы TEST_MAPPING для запуска тестов presubmit в связанных каталогах. С помощью отображения тестов вы можете добавить тот же набор тестов для проверок presubmit с минимальными изменениями в исходном дереве Android.

Посмотрите эти примеры:

Тестовое картирование основано на тестовом оборудовании Trade Federation (TF) для выполнения тестов и предоставления отчетов о результатах.

Определить тестовые группы

Тестовое сопоставление группирует тесты с тестовой группой . Имя тестовой группы может быть любой строкой. Например, presubmit может быть именем для группы тестов, которые будут запущены при проверке изменений. А postsubmit может быть тестами, используемыми для проверки сборок после слияния изменений.

Правила скрипта сборки пакета

Для того чтобы тестовая среда Trade Federation могла запускать тестовые модули для заданной сборки, эти модули должны иметь test_suites установленный для Soong , или LOCAL_COMPATIBILITY_SUITE , установленный для Make, для одного из этих двух наборов:

  • general-tests предназначен для тестов, которые не зависят от возможностей, специфичных для устройства (например, специфичного для поставщика оборудования, которого нет у большинства устройств). Большинство тестов должны быть в наборе general-tests , даже если они специфичны для одного ABI или разрядности или аппаратных функций, таких как HWASan (есть отдельная цель test_suites для каждого ABI), и даже если они должны запускаться на устройстве.
  • device-tests — для тестов, зависящих от возможностей, специфичных для устройства. Обычно эти тесты находятся в vendor/ . Device-specific относится только к возможностям, уникальным для устройства , поэтому это применимо как к тестам JUnit, так и к тестам GTest (которые обычно следует помечать как general-tests даже если они специфичны для ABI).

Примеры:

Android.bp: test_suites: ["general-tests"],
Android.mk: LOCAL_COMPATIBILITY_SUITE := general-tests

Настройте тесты для запуска в тестовом наборе

Для запуска теста внутри тестового набора тест:

  • Не должно быть поставщика сборки.
  • Необходимо выполнить очистку после завершения, например, удалив все временные файлы, созданные во время теста.
  • Необходимо изменить системные настройки на значения по умолчанию или исходные.
  • Не следует предполагать, что устройство находится в определенном состоянии, например, готово к root. Для запуска большинства тестов не требуются привилегии root. Если тесту требуется root, он должен указать это с помощью RootTargetPreparer в своем AndroidTest.xml , как в следующем примере:

    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
    

Создание тестовых файлов сопоставления

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

Следуйте примеру

Вот пример файла TEST_MAPPING (он в формате JSON, но с поддержкой комментариев):

{
  "presubmit": [
    // JUnit test with options and file patterns.
    {
      "name": "CtsWindowManagerDeviceTestCases",
      "options": [
        {
          "include-annotation": "android.platform.test.annotations.RequiresDevice"
        }
      ],
      "file_patterns": ["(/|^)Window[^/]*\\.java", "(/|^)Activity[^/]*\\.java"]
    },
    // Device-side GTest with options.
    {
      "name" : "hello_world_test",
      "options": [
        {
          "native-test-flag": "\"servicename1 servicename2\""
        },
        {
          "native-test-timeout": "6000"
        }
      ]
    }
    // Host-side GTest.
    {
      "name" : "net_test_avrcp",
      "host" : true
    }
  ],
  "postsubmit": [
    {
      "name": "CtsDeqpTestCases",
      "options": [
        {
          // Use regex in include-filter which is supported in AndroidJUnitTest
          "include-filter": "dEQP-EGL.functional.color_clears.*"
        }
      ]
    }
  ],
  "imports": [
    {
      "path": "frameworks/base/services/core/java/com/android/server/am"
    }
  ]
}

Установить атрибуты

В примере presubmit и postsubmit — это имена каждой тестовой группы. Подробнее о тестовых группах см. в разделе Определение тестовых групп.

Вы можете задать имя тестового модуля или имя интеграционного теста Trade Federation (путь к ресурсу тестового XML-файла, например, uiautomator/uiautomator-demo ) в значении атрибута name . Обратите внимание, что поле name не может использовать name класса или name метода теста . Чтобы сузить круг тестов для запуска, используйте такие параметры, как include-filter . См. пример использования include-filter .

Настройка host теста указывает, является ли тест тестом без устройств, запущенным на хосте, или нет. Значение по умолчанию — false , что означает, что для запуска теста требуется устройство. Поддерживаемые типы тестов — HostGTest для двоичных файлов GTest и HostTest для тестов JUnit.

Атрибут file_patterns позволяет задать список строк регулярных выражений для сопоставления относительного пути любого файла исходного кода (относительно каталога, содержащего файл TEST_MAPPING ). В примере тест CtsWindowManagerDeviceTestCases запускается в presubmit только тогда, когда файл Java начинается с Window или Activity , который находится в том же каталоге, что и файл TEST_MAPPING или любой из его подкаталогов. Обратные косые черты (\) необходимо экранировать, поскольку они находятся в файле JSON.

Атрибут imports позволяет включать тесты в другие файлы TEST_MAPPING без копирования содержимого. Файлы TEST_MAPPING в родительских каталогах импортируемого пути также включены. Тестовое сопоставление допускает вложенный импорт; это означает, что два файла TEST_MAPPING могут импортировать друг друга, а тестовое сопоставление может объединять включенные тесты.

Атрибут options содержит дополнительные параметры командной строки Tradefed.

Чтобы получить полный список доступных опций для данного теста, выполните:

tradefed.sh run commandAndExit [test_module] --help

Более подробную информацию о работе опционов можно найти в разделе Обработка опционов в Tradefed .

Проводите тесты с Atest

Чтобы выполнить правила предварительного тестирования локально:

  1. Перейдите в каталог, содержащий файл TEST_MAPPING .
  2. Выполните команду:

    atest
    

Все presubmit-тесты, настроенные в файлах TEST_MAPPING текущего каталога и его родительских каталогов, запускаются. Atest находит и запускает два теста для presubmit (A и B).

Это самый простой способ запустить предварительные тесты в файлах TEST_MAPPING в текущем рабочем каталоге (CWD) и родительских каталогах. Atest находит и использует файл TEST_MAPPING в CWD и всех его родительских каталогах.

Структура исходного кода

В этом примере показано, как можно настроить файлы TEST_MAPPING в исходном дереве:

src
├── project_1
│   └── TEST_MAPPING
├── project_2
│   └── TEST_MAPPING
└── TEST_MAPPING

Содержимое src/TEST_MAPPING :

{
  "presubmit": [
    {
      "name": "A"
    }
  ]
}

Содержимое src/project_1/TEST_MAPPING :

{
  "presubmit": [
    {
      "name": "B"
    }
  ],
  "postsubmit": [
    {
      "name": "C"
    }
  ],
  "other_group": [
    {
      "name": "X"
    }
  ]}

Содержимое src/project_2/TEST_MAPPING :

{
  "presubmit": [
    {
      "name": "D"
    }
  ],
  "import": [
    {
      "path": "src/project_1"
    }
  ]}

Укажите целевые каталоги

Вы можете указать целевой каталог для запуска тестов в файлах TEST_MAPPING в этом каталоге. Следующая команда запускает два теста (A, B):

atest --test-mapping src/project_1

Запустить правила тестирования после отправки

Эту команду также можно использовать для запуска правил тестирования после отправки, определенных в TEST_MAPPING в src_path (по умолчанию CWD) и его родительских каталогах:

atest [--test-mapping] [src_path]:postsubmit

Запускайте только те тесты, которые не требуют устройства.

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

atest [--test-mapping] --host

Определить тестовые группы

Вы можете указать тестовые группы в команде Atest. Следующая команда запускает все тесты postsubmit , связанные с файлами в каталоге src/project_1 , который содержит только один тест (C).

Или вы можете использовать :all для запуска всех тестов независимо от группы. Следующая команда запускает четыре теста (A, B, C, X):

atest --test-mapping src/project_1:all

Включить подкаталоги

По умолчанию запуск тестов в TEST_MAPPING с Atest запускает только presubmit-тесты, настроенные в файле TEST_MAPPING в CWD (или указанном каталоге) и его родительских каталогах. Если вы хотите запустить тесты во всех файлах TEST_MAPPING в подкаталогах, используйте опцию --include-subdir , чтобы заставить Atest включить и эти тесты.

atest --include-subdir

Без параметра --include-subdir Atest запускает только тест A. С параметром --include-subdir Atest запускает два теста (A, B).

Поддерживаются комментарии на уровне строки

Вы можете добавить комментарий формата на уровне строки // , чтобы конкретизировать файл TEST_MAPPING с описанием настройки, которая следует за ним. ATest и Trade Federation предварительно обрабатывают TEST_MAPPING в допустимый формат JSON без комментариев. Чтобы сохранить файл JSON чистым, поддерживается только комментарий формата на уровне строки // .

Пример:

{
  // For presubmit test group.
  "presubmit": [
    {
      // Run test on module A.
      "name": "A"
    }
  ]
}