Esta é uma breve introdução ao Mapeamento de Testes e uma explicação de como começar a configurar testes facilmente no Android Open Source Project (AOSP).
O que é Mapeamento de Teste?
O Test Mapping é uma abordagem baseada em Gerrit que permite aos desenvolvedores criar regras de teste pré e pós-envio diretamente na árvore de origem do Android e deixar as decisões de branches e dispositivos a serem testados para a própria infraestrutura de teste. As definições de mapeamento de teste são arquivos JSON denominados TEST_MAPPING que podem ser colocados em qualquer diretório de origem.
Atest pode usar os arquivos TEST_MAPPING para executar testes de pré-envio nos diretórios associados. Com o Test Mapping, você pode adicionar o mesmo conjunto de testes para pré-enviar verificações com uma simples alteração dentro da árvore de origem do Android.
Veja estes exemplos:
Adicionar testes de pré-envio ao TEST_MAPPING para services.core
Adicione testes de pré-envio ao TEST_MAPPING para ferramentas/dexter usando importações
O Test Mapping conta com o Test Harness da Trade Federation (TF) para execução de testes e relatórios de resultados.
Definindo grupos de teste
Testes de grupos de mapeamento de teste por meio de um grupo de teste . O nome de um grupo de teste pode ser qualquer string. Por exemplo, o pré- envio pode ser para a execução de um grupo de testes ao validar alterações. E os testes pós -envio podem ser usados para validar as compilações após a mesclagem das alterações.
Regras de script de compilação de empacotamento
Para que o Conjunto de Testes da Trade Federation execute os módulos de teste do Test Mapping para uma determinada compilação, esses módulos devem ter test_suite definido para Soong ou LOCAL_COMPATIBILITY_SUITE definido para Make para um destes dois conjuntos:
- general-tests - testes que não dependem da funcionalidade específica do dispositivo (como hardware específico do fornecedor que a maioria dos dispositivos não possui). A maioria dos testes deve estar no conjunto de testes gerais, mesmo que sejam específicos para uma ABI ou recursos de bits ou de hardware como HWASan (há um destino test_suites separado para cada ABI) e mesmo que precisem ser executados em um dispositivo.
- device-tests - testes que dependem da funcionalidade específica do dispositivo. Normalmente, esses testes serão encontrados em
vendor/
. Como "específico do dispositivo" não se refere à funcionalidade ABI ou SoC que outros dispositivos podem ou não ter, mas apenas a funcionalidade exclusiva de um dispositivo, isso se aplica aos testes JUnit tanto quanto aos testes nativos GTest (que geralmente devem sergeneral-tests
mesmo que sejam específicos de ABI).
Exemplos:
Android.bp: test_suites: ["general-tests"],
Android.mk: LOCAL_COMPATIBILITY_SUITE := general-tests
Configurando testes para serem executados em um conjunto de testes
Para que um teste seja executado dentro de um conjunto de testes, o teste:
- não deve ter nenhum provedor de compilação.
- deve limpar depois de concluído, por exemplo, excluindo quaisquer arquivos temporários gerados durante o teste.
- alterar as configurações do sistema para o valor padrão ou original.
- não deve assumir um dispositivo em um determinado estado, por exemplo, pronto para root. A maioria dos testes não requer privilégios de root para ser executado. Se um teste precisar de root, ele deverá especificar isso com um
RootTargetPreparer
em seuAndroidTest.xml
, como no exemplo a seguir:
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
Criando arquivos de mapeamento de teste
Para o diretório que requer cobertura de teste, basta adicionar um arquivo JSON TEST_MAPPING semelhante ao exemplo abaixo. Essas regras garantirão que os testes sejam executados em verificações de pré-envio quando qualquer arquivo for tocado nesse diretório ou em qualquer um de seus subdiretórios.
Seguindo um exemplo
Aqui está um exemplo de arquivo TEST_MAPPING
(está no formato JSON, mas com suporte para comentários):
{
"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"
}
]
}
Configurando atributos
No exemplo acima, presubmit
e postsubmit
são os nomes de cada grupo de teste . Consulte Definindo grupos de teste para obter mais informações sobre grupos de teste.
O nome do módulo de teste ou o nome do teste de integração da Federação de Comércio (caminho do recurso para o arquivo XML de teste, por exemplo, uiautomator/uiautomator-demo ) pode ser definido no valor do atributo name
. Observe que o campo de nome não pode usar name
name
método de teste. Para restringir os testes a serem executados, você pode usar opções como include-filter
aqui. Consulte ( uso de amostra de filtro de inclusão ).
A configuração do host de um teste indica se o teste é um teste sem dispositivo executado no host ou não. O valor padrão é false , o que significa que o teste requer um dispositivo para ser executado. Os tipos de teste suportados são HostGTest para binários GTest e HostTest para testes JUnit.
O atributo file_patterns permite definir uma lista de strings regex para corresponder ao caminho relativo de qualquer arquivo de código-fonte (relativo ao diretório que contém o arquivo TEST_MAPPING). No exemplo acima, o teste CtsWindowManagerDeviceTestCases
será executado em pré-envio somente quando qualquer arquivo java iniciar com Window ou Activity, que existe no mesmo diretório do arquivo TEST_MAPPING ou em qualquer um de seus subdiretórios, for alterado. As barras invertidas \ precisam ser escapadas, pois estão em um arquivo JSON.
O atributo imports permite incluir testes em outros arquivos TEST_MAPPING sem copiar o conteúdo. Observe que 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 um ao outro, e o Test Mapping é capaz de mesclar corretamente os testes incluídos.
O atributo options contém opções adicionais de linha de comando do TradeFed.
Para obter uma lista completa das opções disponíveis para um determinado teste, execute:
tradefed.sh run commandAndExit [test_module] --help
Consulte Manipulação de opções do TradeFed para obter mais detalhes sobre como as opções funcionam.
Executando testes com o Atest
Para executar as regras de teste de pré-envio localmente:
- Vá para 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 seus diretórios pai são executados. O Atest 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) e nos diretórios pai. O Atest localizará e usará o arquivo TEST_MAPPING no CWD e em todos os seus diretórios pai.
Estruturando o código-fonte
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"
}
]}
Especificando 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
Executando regras de teste pós-envio
Você também pode usar este comando para executar as regras de teste postsubmit definidas em TEST_MAPPING em src_path
(padrão para CWD) e seus diretórios pai:
atest [--test-mapping] [src_path]:postsubmit
Executando apenas testes que não exigem dispositivo
Você pode usar a opção --host para Atest para executar apenas testes configurados no host que não exigem nenhum dispositivo. Sem esta opção, o Atest executará ambos os testes, os que exigem dispositivo e os que são executados no host e não requerem dispositivo. Os testes serão executados em duas suítes separadas.
atest [--test-mapping] --host
Identificando 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
Incluindo 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 em CWD (ou determinado diretório) e seus diretórios pai. Se você deseja executar testes em todos os arquivos TEST_MAPPING nos subdiretórios, use a opção --include --include-subdir
subdir para forçar o Atest a incluir esses testes também.
atest --include-subdir
Sem a opção --include-subdir
-subdir, o Atest executará apenas o teste A. Com a opção --include-subdir
-subdir, o Atest executará dois testes (A, B).
O comentário em nível de linha é compatível
Você pode adicionar um comentário //
-formato em nível de linha para detalhar o arquivo TEST_MAPPING com uma descrição da configuração a seguir. A ATest and Trade Federation 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 o comentário //
-formato no nível da linha é suportado.
Exemplo:
{
// For presubmit test group.
"presubmit": [
{
// Run test on module A.
"name": "A"
}
]
}