Criar um executor de testes do Tradefed

Esta página descreve como escrever um novo executor de testes no Tradefed.

Contexto

Se você quiser saber mais sobre o lugar dos executores de teste na arquitetura do Tradefed, consulte Estrutura de um executor de teste.

Isso não é um pré-requisito para escrever um novo executor de testes. Os executores de testes podem ser escritos isoladamente.

Mínimo necessário: implementar a interface

O mínimo necessário para se qualificar como um executor de testes do Tradefed é implementar a interface IRemoteTest e, mais especificamente, o método run(TestInformation testInfo, ITestInvocationListener listener).

Esse método é invocado pelo conector quando se usa o executor de testes, semelhante a um Java Runnable.

Cada parte desse método é considerada parte da execução do executor de testes.

Informar resultados do executor de testes

O método run na interface básica dá acesso a um objeto listener do tipo ITestInvocationListener. Esse objeto é a chave para informar resultados estruturados do executor de testes para o harness.

Ao informar resultados estruturados, um executor de testes tem as seguintes propriedades:

  • Informe uma lista adequada de todos os testes executados, quanto tempo eles levaram e se foram aprovados, reprovados ou em outros estados individualmente.
  • Informe as métricas associadas aos testes, se aplicável, por exemplo, métricas de tempo de instalação.
  • Se encaixam na maioria das ferramentas de infraestrutura, por exemplo, resultados e métricas de exibição etc.
  • Geralmente é mais fácil depurar, já que há um rastreamento mais granular da execução.

No entanto, a geração de relatórios de resultados estruturados é opcional. Um executor de testes pode simplesmente querer avaliar o estado de toda a execução como APROVADO ou REPROVADO, sem detalhes da execução real.

Os seguintes eventos podem ser chamados no listener para notificar o arnês do progresso atual das execuções:

  • testRunStarted: notifica o início de um grupo de casos de teste relacionados.
    • testStarted: notifica o início de um caso de teste.
    • testFailed/testIgnored: notifica a mudança de estado do caso de teste em andamento. Um caso de teste sem mudança de estado é considerado aprovado.
    • testEnded: notifica o fim do caso de teste.
  • testRunFailed: notifica que o status geral da execução do grupo de casos de teste é uma falha. Uma execução de teste pode ser aprovada ou reprovada independente dos resultados dos casos de teste, dependendo do que a execução esperava. Por exemplo, um binário que executa vários casos de teste pode informar todos os casos de teste aprovados, mas com um código de saída de erro (por qualquer motivo: arquivos vazados etc.).
  • testRunEnded: notifica o fim do grupo de casos de teste.

Manter e garantir a ordem correta dos callbacks é responsabilidade do implementador do executor de testes. Por exemplo, garantir que testRunEnded seja chamado em caso de exceção usando uma cláusula finally.

Os callbacks de casos de teste (testStarted, testEnded etc.) são opcionais. Uma execução de teste pode ocorrer sem casos de teste.

Você vai notar que essa estrutura de eventos é inspirada na estrutura típica do JUnit. Isso é proposital para manter as coisas próximas de algo básico que os desenvolvedores geralmente conhecem.

Informar registros do executor de testes

Se você estiver escrevendo sua própria classe ou executor de teste do Tradefed, implemente IRemoteTest e receba um ITestInvocationListener pelo método run(). Esse listener pode ser usado para registrar arquivos da seguinte maneira:

    listener.testLog(String dataName, LogDataType type_of_data, InputStreamSource data);

Testar com um dispositivo

A interface mínima acima permite executar testes muito simples que são isolados e não exigem recursos específicos, por exemplo, testes de unidade Java.

Os criadores de testes que querem passar para a próxima etapa de teste de dispositivo precisam das seguintes interfaces:

  • A IDeviceTest permite receber o objeto ITestDevice que representa o dispositivo em teste e fornece a API para interagir com ele.
  • O IBuildReceiver permite que o teste receba o objeto IBuildInfo criado na etapa do provedor de build que contém todas as informações e artefatos relacionados à configuração do teste.

Os executores de teste geralmente se interessam por essas interfaces para receber artefatos relacionados à execução, por exemplo, arquivos extras, e receber o dispositivo em teste que será segmentado durante a execução.

Testar com vários dispositivos

O Tradefed permite executar testes em vários dispositivos ao mesmo tempo. Isso é útil ao testar componentes que exigem uma interação externa, como um pareamento de smartphone e relógio.

Para gravar um executor de testes que possa usar vários dispositivos, é necessário implementar a IMultiDeviceTest, que permite receber um mapa de ITestDevice para IBuildInfo que contém a lista completa de representações de dispositivos e as informações de build associadas.

O setter da interface sempre é chamado antes do método run. Portanto, é seguro presumir que a estrutura estará disponível quando run for chamado.

Testes que conhecem as configurações

Algumas implementações de executores de teste podem precisar de informações sobre a configuração geral para funcionar corretamente, por exemplo, alguns metadados sobre a invocação ou qual target_preparer foi executado antes etc.

Para isso, um executor de teste pode acessar o objeto IConfiguration de que faz parte e em que é executado. Consulte a descrição do objeto de configuração para mais detalhes.

Para a implementação do executor de testes, você precisa implementar o IConfigurationReceiver para receber o objeto IConfiguration.

Executor de testes flexível

Os executores de testes podem oferecer uma maneira flexível de executar os testes se tiverem um controle granular sobre eles. Por exemplo, um executor de testes do JUnit pode executar individualmente cada teste de unidade.

Isso permite que o conector e a infraestrutura maiores aproveitem esse controle refinado e que os usuários executem parcialmente o executor de testes usando a filtragem.

O suporte à filtragem é descrito na interface ITestFilterReceiver, que permite receber conjuntos de filtros include e exclude para os testes que devem ou não ser executados.

Nossa convenção é que um teste será executado SE ele corresponder a um ou mais filtros de inclusão E não corresponder a nenhum filtro de exclusão. Se nenhum filtro de inclusão for fornecido, todos os testes serão executados, desde que não correspondam a nenhum dos filtros de exclusão.