Mapeamento de teste

Esta é uma breve introdução ao mapeamento de testes e uma explicação sobre como começar a configurar testes com facilidade no Android Open Source Project (AOSP).

Sobre o mapeamento de testes

O mapeamento de testes é uma abordagem baseada em Gerrit que permite que os desenvolvedores criem regras de teste antes e pós-envio diretamente na árvore de origem do Android e deixem as decisões de ramificações e dispositivos serem testadas na infraestrutura de teste. As definições de mapeamento de teste são arquivos JSON chamados TEST_MAPPING que podem ser colocados em qualquer diretório de origem.

O Atest pode usar os arquivos TEST_MAPPING para executar testes de pré-envio nos diretórios associados. Com o mapeamento de testes, é possível adicionar o mesmo conjunto de testes para pré-enviar verificações com uma simples mudança dentro da árvore de origem do Android.

Confira estes exemplos:

Adicionar testes de pré-envio a TEST_MAPPING para services.core

Adicionar testes de pré-envio a TEST_MAPPING para ferramentas/dexter usando importações

O mapeamento de testes depende do arcabouço de testes da Trade Federation (TF) para a execução de testes e a geração de relatórios de resultados.

Definir grupos de teste

Teste grupos de mapeamento usando um grupo de teste. O nome de um grupo de teste pode ser qualquer string. Por exemplo, presubmit pode ser para que um grupo de testes seja executado ao validar mudanças. Os testes postsubmit podem ser usados para validar os builds depois que as alterações são mescladas.

Regras de script de compilação do pacote

Para que o arcabouço de testes da Trade Federation execute módulos de teste de mapeamento de teste para um determinado build, esses módulos precisam ter test_suites definido como Soong ou LOCAL_COMPATIBILITY_SUITE definido para o Make como um destes dois pacotes:

  • general-tests: testes que não dependem de funcionalidades específicas do dispositivo, como hardware específico do fornecedor que a maioria dos dispositivos não tem. A maioria dos testes precisa estar no pacote de testes gerais, mesmo que sejam específicos de uma ABI, um bitness ou recursos de hardware como o HWASan (há um destino test_suites separado para cada ABI) e mesmo que eles precisem ser executados em um dispositivo.
  • device-tests: testes que dependem de uma funcionalidade específica do dispositivo. Normalmente, esses testes são encontrados em vendor/. Como "específico do dispositivo" não se refere à funcionalidade da ABI ou do SoC que outros dispositivos podem ou não ter, mas sim à funcionalidade exclusiva de um dispositivo, isso se aplica aos testes do JUnit tanto quanto aos testes nativos do GTest (que geralmente precisam ser general-tests, mesmo que sejam específicos da ABI).

Exemplos:

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

Configurar testes para serem executados em um pacote de testes

Para que um teste seja executado dentro de um pacote de testes, o teste:

  • não pode ter nenhum provedor de build.
  • precisa ser limpo após a conclusão, por exemplo, excluindo todos os arquivos temporários gerados durante o teste.
  • mudar as configurações do sistema para o valor padrão ou original.
  • não pode presumir que um dispositivo está em um determinado estado, por exemplo, pronto para o raiz. A maioria dos testes não requer privilégio de raiz para ser executada. Se um teste precisar exigir acesso root, ele precisará especificar isso com um RootTargetPreparer no AndroidTest.xml, como no exemplo a seguir:
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>

Criar arquivos de mapeamento de teste

Para o diretório que exige cobertura de teste, basta adicionar um arquivo JSON TEST_MAPPING semelhante ao exemplo abaixo. Essas regras vão garantir que os testes sejam executados em verificações de pré-envio quando algum arquivo for tocado nesse diretório ou em qualquer um dos subdiretórios.

Siga um exemplo

Veja um exemplo de arquivo TEST_MAPPING (está no formato JSON, mas com comentários compatíveis):

{
  "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"
    }
  ]
}

Definir atributos

No exemplo acima, presubmit e postsubmit são os nomes de cada grupo de teste. Consulte Definir grupos de teste para mais informações sobre grupos de teste.

O nome do módulo de teste ou o nome do teste de integração da Trade Federation (caminho do recurso para o arquivo XML de teste, por exemplo, uiautomator/uiautomator-demo) pode ser definido no valor do atributo name. O campo name não pode usar a classe name ou o método de teste name. Para restringir os testes a serem executados, use opções como include-filter aqui. Consulte (incluir uso de amostra de filtro).

A configuração de host de um teste indica se o teste é sem dispositivo em execução no host ou não. O valor padrão é false, o que significa que o teste exige um dispositivo para ser executado. Os tipos de teste com suporte são HostGTest para binários do GTest e HostTest para testes JUnit.

O atributo file_patterns permite configurar uma lista de strings de regex para corresponder ao caminho relativo de qualquer arquivo de código-fonte (em relação ao diretório que contém o arquivo TEST_MAPPING). No exemplo acima, o teste CtsWindowManagerDeviceTestCases será executado no pré-envio somente quando qualquer arquivo Java começar com Window ou Activity, que existe no mesmo diretório do arquivo TEST_MAPPING ou em qualquer um dos subdiretórios, for alterado. As barras invertidas \ precisam ser escapadas, como em um arquivo JSON.

O atributo imports permite incluir testes em outros arquivos TEST_MAPPING sem copiar o conteúdo. Os arquivos TEST_MAPPING nos diretórios pai do caminho importado também serão incluídos. O mapeamento de teste permite importações aninhadas. Isso significa que dois arquivos TEST_MAPPING podem importar uns aos outros, e o mapeamento de teste pode mesclar corretamente os testes incluídos.

O atributo options contém opções adicionais de linha de comando do TradeFed.

Para conferir uma lista completa das opções disponíveis em um determinado teste, execute:

tradefed.sh run commandAndExit [test_module] --help

Consulte Processamento de opções negociadas para mais detalhes sobre como as opções funcionam.

Executar testes com o Atest

Para executar as regras de teste de pré-envio localmente:

  1. Acesse o diretório que contém o arquivo TEST_MAPPING.
  2. Execute o comando:
atest

Todos os testes de pré-envio configurados nos arquivos TEST_MAPPING do diretório atual e dos diretórios pais são executados. O Atest vai localizar e executar dois testes para pré-envio (A e B).

Essa é a maneira mais simples de executar testes de pré-envio em arquivos TEST_MAPPING no diretório de trabalho atual (CWD, na sigla em inglês) e nos diretórios pai. O Atest localizará e usará o arquivo TEST_MAPPING no CWD e todos os diretórios pais.

Código-fonte da estrutura

O exemplo a seguir mostra como os arquivos TEST_MAPPING podem ser configurados na árvore de origem.

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

Conteúdo de src/TEST_MAPPING:

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

Conteúdo de src/project_1/TEST_MAPPING:

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

Conteúdo de src/project_2/TEST_MAPPING:

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

Especificar diretórios de destino

Você pode especificar um diretório de destino para executar testes em arquivos TEST_MAPPING nesse diretório. O comando a seguir executará dois testes (A, B).

atest --test-mapping src/project_1

Executar regras de teste pós-envio

Também é possível usar esse comando para executar as regras de teste de pós-envio definidas em TEST_MAPPING em src_path (o padrão é CWD) e seus diretórios pais:

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

Executar apenas testes que não exigem dispositivo

Você pode usar a opção --host para o Atest para executar apenas testes configurados no host que não exigem dispositivo. Sem essa opção, o Atest executará os dois testes, os que exigem dispositivo e os que estão em execução no host, sem precisar de dispositivo. Os testes serão executados em dois pacotes separados.

atest [--test-mapping] --host

Identificar grupos de teste

Você pode especificar grupos de teste no comando "Atest". O comando a seguir executará todos os testes postsubmit relacionados aos arquivos no diretório src/project_1, que contém apenas um teste (C).

Ou você pode usar :all para executar todos os testes, independentemente do grupo. O comando a seguir executa quatro testes (A, B, C, X):

atest --test-mapping src/project_1:all

Incluir subdiretórios

Por padrão, a execução de testes em TEST_MAPPING com Atest executará apenas testes de pré-envio configurados no arquivo TEST_MAPPING no CWD (ou diretório determinado) e nos diretórios pais. Se você quiser executar testes em todos os arquivos TEST_MAPPING nos subdiretórios, use a opção --include-subdir para forçar o Atest a incluir esses testes também.

atest --include-subdir

Sem a opção --include-subdir, o Atest executará apenas o teste A. Com a opção --include-subdir, o Atest vai executar dois testes (A, B).

Comentários no nível da linha são aceitos

É possível adicionar um comentário no formato // no nível da linha para detalhar o arquivo TEST_MAPPING com uma descrição da configuração a seguir. O ATest e a Trade Federation vão pré-processar o TEST_MAPPING para um formato JSON válido sem comentários. Para manter o arquivo JSON limpo e fácil de ler, apenas comentários no formato // no nível da linha são aceitos.

Exemplo:

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