Esta é uma breve introdução ao mapeamento de testes e uma explicação de como começar a configurar testes no Android Open Source Project (AOSP).
Sobre o mapeamento de testes
O mapeamento de testes é uma abordagem baseada no Gerrit que permite aos desenvolvedores criar regras de teste de pré-envio e pós-envio diretamente na árvore de origem do Android e deixar as decisões de ramificações e dispositivos a serem testados para a infraestrutura de teste.
As definições de mapeamento de testes 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 às verificações de pré-envio com uma mudança mínima na árvore de origem do Android.
Confira estes exemplos:
Adicionar testes de pré-envio ao
TEST_MAPPINGparaservices.coreAdicionar testes de pré-envio ao
TEST_MAPPINGparatools/dexterusando importações
O mapeamento de testes depende da estrutura de teste do Trade Federation (TF) para execução de testes e relatórios de resultados.
Definir grupos de teste
O mapeamento de testes agrupa testes com um grupo de testes. O nome de um grupo de testes pode ser qualquer string. Por exemplo, presubmit pode ser o nome de um grupo de testes a serem executados ao validar mudanças. E postsubmit podem ser os testes usados para validar os builds após a mesclagem das mudanças.
Regras de script de build de pacote
Para que a estrutura de teste do Trade Federation
execute módulos de teste para um determinado build, esses módulos precisam ter um
test_suites conjunto para Soong ou um LOCAL_COMPATIBILITY_SUITE conjunto
para Make em uma destas duas suítes:
general-testsé para testes que não dependem de recursos específicos do dispositivo (como hardware específico do fornecedor que a maioria dos dispositivos não tem). A maioria dos testes precisa estar na suítegeneral-tests, mesmo que sejam específicos para uma ABI, bitness ou recursos de hardware, como HWASan (há um destinotest_suitesseparado para cada ABI), e mesmo que precisem ser executados em um dispositivo.device-testsé para testes que dependem de recursos específicos do dispositivo. Normalmente, esses testes são encontrados emvendor/. Específico do dispositivo refere-se apenas a recursos exclusivos de um dispositivo. Portanto, isso se aplica a testes JUnit e GTest (que geralmente precisam ser marcados comogeneral-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 execução em um conjunto de testes
Para que um teste seja executado dentro de um conjunto de testes, ele:
- Não pode ter um provedor de build.
- Precisa ser limpo após a conclusão, por exemplo, excluindo todos os arquivos temporários gerados durante o teste.
- Precisa mudar as configurações do sistema para o valor padrão ou original.
Não pode presumir que um dispositivo esteja em um determinado estado, por exemplo, pronto para raiz. A maioria dos testes não exige privilégio de raiz para execução. Se um teste precisar de raiz, ele precisará especificar isso com
RootTargetPreparerno seuAndroidTest.xml, como no exemplo a seguir:<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
Criar arquivos de mapeamento de testes
Para o diretório que exige cobertura de teste, adicione um arquivo JSON TEST_MAPPINGsemelhante ao exemplo. Essas regras garantem que os testes sejam executados em verificações de pré-envio quando qualquer arquivo for acessado nesse diretório ou em qualquer um dos subdiretórios.
Seguir um exemplo
Confira um exemplo de arquivo TEST_MAPPING (está no formato JSON, mas com comentários aceitos):
{
"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"
}
]
}
Definir atributos
No exemplo, presubmit e postsubmit são os nomes de cada
grupo de testes. Consulte Definir grupos de teste para mais informações
sobre grupos de testes.
É possível definir o nome do módulo de teste ou o nome do teste de integração do Trade Federation (caminho do recurso para o arquivo XML de teste, por exemplo,
uiautomator/uiautomator-demo)
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. Consulte o
include-filter exemplo de uso.
A configuração host de um teste indica se o teste é um 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 execução. Os tipos de teste aceitos são
HostGTest para
binários GTest e HostTest para testes JUnit.
O atributo file_patterns permite definir uma lista de strings de expressão regular para correspondência do caminho relativo de qualquer arquivo de código-fonte (relativo ao diretório que contém o arquivo TEST_MAPPING). No exemplo,
teste CtsWindowManagerDeviceTestCases é executado no pré-envio somente quando um arquivo Java
começa com Window ou Activity, que existe no mesmo diretório que o arquivo
TEST_MAPPING ou qualquer um dos subdiretórios. As barras invertidas (\) precisam ser
escapadas, já que estão em um arquivo JSON.
Importar arquivos TEST_MAPPING
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 são incluídos. TEST_MAPPING permite importações aninhadas, o que significa que os arquivos importados podem importar outros arquivos TEST_MAPPING, e o mapeamento de testes pode mesclar os testes incluídos.
TEST_MAPPING oferece suporte a importações no nível raiz e no nível do grupo:
- Importações no nível raiz:especificadas no nível superior do arquivo
TEST_MAPPING(fora de qualquer grupo de testes). Uma importação no nível raiz importa todo o arquivoTEST_MAPPINGde destino (e os diretórios pai dele) como se ele tivesse sido gravado no caminho para o qual está sendo importado. Todas as definições de grupo de testes no arquivo importado (por exemplo,presubmit,postsubmit) são mescladas nos grupos de testes correspondentes do arquivo de importação. - Importações no nível do grupo:especificadas diretamente dentro de um grupo de testes específico (como
presubmitoupostsubmit). Uma importação no nível do grupo é definida estritamente para esse grupo de testes, o que significa que apenas os testes definidos nesse grupo específico no arquivoTEST_MAPPINGde destino serão importados. Todos os outros grupos de testes no arquivo de destino são ignorados.
As importações no nível do grupo oferecem controle refinado sobre a execução do teste. Por exemplo, é possível importar testes especificamente para pré-envio sem extrair testes de pós-envio pesados do diretório importado.
Exemplo de uma importação no nível raiz:
{
"imports": [
{
"path": "frameworks/base/services/core"
}
],
"presubmit": [
{
"name": "MyTestModule"
}
]
}
Exemplo de uma importação no nível do grupo:
{
"presubmit": [
{
"name": "MyTestModule"
},
{
"imports": [
{
"path": "frameworks/base/services/core"
}
]
}
],
"postsubmit": [
{
"imports": [
{
"path": "frameworks/base/services/accessibility"
}
]
}
]
}
O atributo options contém outras opções de linha de comando do Tradefed.
Para conferir uma lista completa de opções disponíveis para um determinado teste, execute:
tradefed.sh run commandAndExit [test_module] --help
Consulte Processamento de opções no Tradefed para mais detalhes sobre como as opções funcionam.
Validações TEST_MAPPING
Ao enviar mudanças que modificam arquivos TEST_MAPPING, as verificações de pré-envio são executadas para garantir a correção:
- Validação de padrões de arquivo:garante que todas as expressões regulares em
file_patternscorrespondam a pelo menos um arquivo no repositório. Padrões desatualizados que não correspondem a nenhum arquivo causam a falha da verificação. - Validação no momento do build:promove avisos de validação no momento do build que o build coleta para bloquear erros no pré-envio de ramificações principais. Os avisos comuns incluem:
- Módulos inexistentes:referenciar um nome de módulo de teste que não existe na base de código, como quando o nome tem um erro de digitação.
- Importações inválidas:caminhos de referência em
importsque não existem ou não contêm um arquivoTEST_MAPPING. - Problemas de esquema:usar chaves não aceitas ou estruturas malformadas na configuração JSON.
Executar testes com o Atest
Para executar as regras de teste de pré-envio localmente:
- Acesse o diretório que contém o arquivo
TEST_MAPPING. Execute o comando:
atest
Todos os testes de pré-envio configurados nos arquivos TEST_MAPPING do diretório atual e dos diretórios pai são executados. O Atest localiza e executa 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 localiza e usa o arquivo TEST_MAPPING no CWD e em todos os diretórios pai.
Estruturar o código-fonte
Este exemplo mostra como configurar arquivos TEST_MAPPING 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
É possível especificar um diretório de destino para executar testes em arquivos TEST_MAPPING nesse diretório. O comando a seguir executa dois testes (A, B):
atest --test-mapping src/project_1
Executar regras de teste de 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 (padrão para CWD) e nos diretórios pai:
atest [--test-mapping] [src_path]:postsubmit
Executar apenas testes que não exigem um dispositivo
É possível usar a opção --host para que o Atest execute apenas os testes configurados no host que não exigem um dispositivo. Sem essa opção, o Atest executa os dois testes, aqueles que exigem um dispositivo e aqueles que são executados em um host que não exige um dispositivo. Os testes são executados em duas suítes separadas:
atest [--test-mapping] --host
Identificar grupos de teste
É possível especificar grupos de teste no comando Atest. O comando a seguir executa todos os testes postsubmit relacionados a arquivos no diretório src/project_1, que contém apenas um teste (C).
Ou é possível 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 o Atest executa apenas testes de pré-envio configurados no arquivo TEST_MAPPING no CWD (ou diretório fornecido) e nos diretórios pai. 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 executa apenas o teste A. Com a opção --include-subdir, o Atest executa dois testes (A, B).
Comentário no nível da linha aceito
É possível adicionar um comentário de formato // no nível da linha para preencher o arquivo TEST_MAPPING com uma descrição da configuração a seguir.
ATest e Trade Federation
pré-processam TEST_MAPPING para um formato JSON válido sem comentários. Para manter o arquivo JSON limpo, apenas o comentário de formato // no nível da linha é aceito.
Exemplo:
{
// For presubmit test group.
"presubmit": [
{
// Run test on module A.
"name": "A"
}
]
}