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

Это краткое введение в сопоставление тестов и объяснение того, как приступить к настройке тестов в проекте Android с открытым исходным кодом (AOSP).

О тестовом сопоставлении

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

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

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

Сопоставление тестов основано на тестовых комплектах Торговой федерации (TF) для выполнения тестов и отчетности о результатах.

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

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

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

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

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