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

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

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

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

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

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

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

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

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

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

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

  • general-tests предназначен для тестов, не зависящих от возможностей конкретного устройства (например, оборудования, специфичного для конкретного производителя, которого нет у большинства устройств). Большинство тестов должны быть включены в набор general-tests , даже если они специфичны для одного ABI, разрядности или аппаратных функций, таких как HWASan (для каждого ABI существует отдельный целевой набор test_suites ), и даже если они должны запускаться на устройстве.
  • 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
    

Выполняются все предварительные тесты, настроенные в файлах TEST_MAPPING текущего каталога и его родительских каталогов. Atest находит и запускает два предварительных теста (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 запускает только предварительные тесты, настроенные в файле 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"
    }
  ]
}