O Google está comprometido em promover a equidade racial para as comunidades negras. Veja como.
Esta página foi traduzida pela API Cloud Translation.
Switch to English

Exemplo de testes auto-instrumentados

Quando um teste de instrumentação é iniciado, seu pacote de destino é reiniciado com o código de instrumentação injetado e iniciado para execução. Uma exceção é que o pacote de destino aqui não pode ser a própria estrutura do aplicativo Android, ou seja, o pacote android , porque isso levaria a uma situação paradoxal em que a estrutura do Android precisaria ser reiniciada, e é isso que suporta as funções do sistema, incluindo a instrumentação em si.

Isso significa que um teste de instrumentação não pode se injetar na estrutura do Android, também conhecido como servidor do sistema, para execução. Para testar a estrutura do Android, o código de teste pode chamar apenas superfícies públicas da API ou expostas pelo AIDL da Linguagem de Definição de Interface do Android, disponível na árvore de origem da plataforma. Para esta categoria de testes, não faz sentido segmentar um pacote específico. Portanto, é habitual que essas instrumentações sejam declaradas para atingir seu próprio pacote de aplicativos de teste, conforme definido em sua própria tag <manifest> do AndroidManifest.xml .

Dependendo dos requisitos, os pacotes de aplicativos de teste nessa categoria também podem:

  • Agrupe as atividades necessárias para o teste.
  • Compartilhe o ID do usuário com o sistema.
  • Ser assinado com a chave da plataforma.
  • Seja compilado com base na origem da estrutura e não no SDK público.

Essa categoria de testes de instrumentação é algumas vezes referida como auto-instrumentação. Aqui estão alguns exemplos de testes de auto-instrumentação na fonte da plataforma:

O exemplo abordado aqui está escrevendo um novo teste de instrumentação com o pacote de destino definido em seu próprio pacote de aplicativos de teste. Este guia usa o seguinte teste para servir como exemplo:

É recomendável navegar pelo código primeiro para obter uma impressão aproximada antes de continuar.

Decidindo sobre um local de origem

Normalmente, sua equipe já terá um padrão estabelecido de locais para check-in de código e locais para adicionar testes. A maioria das equipes possui um único repositório git ou compartilha um com outras equipes, mas possui um subdiretório dedicado que contém o código-fonte do componente.

Supondo que o local raiz da origem do componente esteja em <component source root> , a maioria dos componentes possui pastas src e tests e alguns arquivos adicionais, como Android.mk (ou divididos em arquivos .mk adicionais), o arquivo de manifesto AndroidManifest.xml e o arquivo de configuração de teste 'AndroidTest.xml'.

Como você está adicionando um teste totalmente novo, provavelmente precisará criar o diretório de tests próximo ao src componente e preenchê-lo com conteúdo.

Em alguns casos, sua equipe pode ter estruturas de diretórios adicionais sob tests devido à necessidade de empacotar diferentes conjuntos de testes em aplicativos individuais. E, nesse caso, você precisará criar um novo subdiretório sob tests .

Independentemente da estrutura, você acabará preenchendo o diretório de tests ou o subdiretório recém-criado com arquivos semelhantes ao que está no diretório de instrumentation na alteração de amostra de gerrit. As seções abaixo explicam mais detalhes de cada arquivo.

Arquivo de manifesto

Assim como um aplicativo regular, cada módulo de teste de instrumentação precisa de um arquivo de manifesto. Se você nomear o arquivo como AndroidManifest.xml e fornecê-lo ao lado de Android.mk para o seu módulo de teste, ele será incluído automaticamente pelo makefile do núcleo BUILD_PACKAGE .

Antes de prosseguir, é altamente recomendável acessar primeiro a Visão geral do manifesto do aplicativo .

Isso fornece uma visão geral dos componentes básicos de um arquivo de manifesto e suas funcionalidades. Veja o exemplo em platform_testing / tests / example / instrumentation / AndroidManifest.xml .

Um instantâneo está incluído aqui por conveniência:

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />

    <application>
        <uses-library android:name="android.test.runner" />
    </application>

    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                     android:targetPackage="android.test.example.helloworld"
                     android:label="Hello World Test"/>

</manifest>
 

Algumas observações selecionadas no arquivo de manifesto:

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >
 

O atributo package é o nome do pacote do aplicativo: este é o identificador exclusivo que a estrutura do aplicativo Android usa para identificar um aplicativo (ou, neste contexto: seu aplicativo de teste). Cada usuário no sistema pode instalar apenas um aplicativo com esse nome de pacote.

Além disso, esse atributo do package é o mesmo que o ComponentName#getPackageName() retorna e também o mesmo que você usaria para interagir com vários comandos sub da pm via adb shell .

Observe também que, embora o nome do pacote normalmente esteja no mesmo estilo que o nome de um pacote Java, ele realmente tem muito pouco a ver com isso. Em outras palavras, seu pacote de aplicativos (ou teste) pode conter classes com qualquer nome de pacote, embora, por outro lado, você possa optar pela simplicidade e ter seu nome de pacote Java de nível superior em seu aplicativo ou teste idêntico ao nome do pacote de aplicativos.

 android:sharedUserId="android.uid.system"
 

Isso declara que, no momento da instalação, esse apk deve receber o mesmo ID do usuário, ou seja, a identidade do tempo de execução, que a plataforma principal. Observe que isso depende do fato de o apk ser assinado com o mesmo certificado da plataforma principal (consulte LOCAL_CERTIFICATE na seção acima), mas são conceitos diferentes:

  • algumas permissões ou APIs são protegidas por assinatura, o que requer o mesmo certificado de assinatura
  • algumas permissões ou APIs requerem a identidade do usuário do system do chamador, o que exige que o pacote de chamada compartilhe a identificação do usuário com o system , se for um pacote separado da própria plataforma principal
 <uses-library android:name="android.test.runner" />
 

Isso é necessário para todos os testes de instrumentação, pois as classes relacionadas são empacotadas em um arquivo de biblioteca jar da estrutura separada, portanto, requerem entradas adicionais do caminho de classe quando o pacote de teste é chamado pela estrutura do aplicativo.

 android:targetPackage="android.test.example.helloworld"
 

Você deve ter notado que o targetPackage aqui é declarado igual ao atributo do package declarado na marca de manifest deste arquivo. Conforme mencionado nos princípios básicos do teste , essa categoria de teste de instrumentação geralmente é destinada a APIs da estrutura de teste, portanto, não faz muito sentido que eles tenham um pacote de aplicativos direcionado específico, além dele próprio.

Arquivo de configuração simples

Cada novo módulo de teste deve ter um arquivo de configuração para direcionar o sistema de compilação com metadados do módulo, dependências em tempo de compilação e instruções de empacotamento. Na maioria dos casos, a opção de arquivo Blueprint baseada em Soong é suficiente. Para detalhes, consulte Configuração de Teste Simples .

Arquivo de configuração complexo

Para esses casos mais complexos, você também precisa escrever um arquivo de configuração de teste para o equipamento de teste do Android, a Trade Federation .

A configuração de teste pode especificar opções especiais de configuração do dispositivo e argumentos padrão para fornecer a classe de teste. Veja o exemplo em /platform_testing/tests/example/instrumentation/AndroidTest.xml .

Um instantâneo está incluído aqui por conveniência:

 <configuration description="Runs sample instrumentation test.">
  <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
  <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    <option name="test-file-name" value="HelloWorldTests.apk"/>
  </target_preparer>
  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
  <option name="test-suite-tag" value="apct"/>
  <option name="test-tag" value="SampleInstrumentationTest"/>

  <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    <option name="package" value="android.test.example.helloworld"/>
    <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
  </test>
</configuration>
 

Algumas observações selecionadas no arquivo de configuração de teste:

 <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
  <option name="test-file-name" value="HelloWorldTests.apk"/>
</target_preparer>
 

Isso informa ao Trade Federation para instalar o HelloWorldTests.apk no dispositivo de destino usando um target_preparer especificado. Existem muitos preparadores de destino disponíveis para desenvolvedores na Federação do Comércio e eles podem ser usados ​​para garantir que o dispositivo seja configurado corretamente antes da execução do teste.

 <test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="android.test.example.helloworld"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>
 

Isso especifica a classe de teste da Federação de Comércio a ser usada para executar o teste e passa no pacote no dispositivo a ser executado e a estrutura do executor de teste que é JUnit neste caso.

Para mais informações, consulte Configurações do módulo de teste .

Recursos do JUnit4

O uso da biblioteca android-support-test como executor de testes permite a adoção de novas classes de teste no estilo JUnit4, e a mudança de amostra de gerrit contém um uso muito básico de seus recursos. Veja o exemplo em /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java .

Embora os padrões de teste geralmente sejam específicos para as equipes de componentes, existem alguns padrões de uso geralmente úteis.

 @RunWith(JUnit4.class)
public class HelloWorldTest {
 

Uma diferença significativa no JUnit4 é que os testes não precisam mais herdar de uma classe de teste básica comum; em vez disso, você escreve testes em classes Java simples e usa anotação para indicar determinadas configurações e restrições de teste. Neste exemplo, estamos instruindo que essa classe deve ser executada como um teste JUnit4.

     @BeforeClass
    public static void beforeClass() {
    ...
    @AfterClass
    public static void afterClass() {
    ...
    @Before
    public void before() {
    ...
    @After
    public void after() {
    ...
    @Test
    @SmallTest
    public void testHelloWorld() {
    ...
 

Os @Before e @After anotações são usados em métodos de JUnit4 para executar configuração de teste pré e desmontagem pós teste. Da mesma forma, os @BeforeClass e @AfterClass anotações são usados em métodos de JUnit4 para executar a configuração antes de executar todos os testes em uma classe de teste, e desmontagem depois. Observe que os métodos de instalação e desmontagem no escopo da classe devem ser estáticos. Quanto aos métodos de teste, diferentemente da versão anterior do JUnit, eles não precisam mais iniciar o nome do método com test . Em vez disso, cada um deles deve ser anotado com @Test . Como de costume, os métodos de teste devem ser públicos, declarar sem valor de retorno, sem parâmetros e podem gerar exceções.

Importante : os próprios métodos de teste são anotados com a anotação @Test ; e observe que, para que os testes sejam executados via APCT, eles devem ser anotados com tamanhos de teste: o exemplo do método anotado testHelloWorld como @SmallTest . A anotação pode ser aplicada no escopo do método ou no escopo da classe.

Acessando a instrumentation

Embora não seja abordado no exemplo básico do Hello World, é bastante comum que um teste do Android exija acesso à instância Instrumentation : esta é a interface principal da API que fornece acesso a contextos de aplicativos, APIs de teste relacionadas ao ciclo de vida da atividade e muito mais.

Como os testes JUnit4 não exigem mais uma classe base comum, não é mais necessário obter a instância Instrumentation via InstrumentationTestCase#getInstrumentation() ; em vez disso, o novo InstrumentationTestCase#getInstrumentation() teste o gerencia via InstrumentationRegistry onde a configuração contextual e ambiental criada pela estrutura de instrumentação é armazenada.

Para acessar a instância da classe Instrumentation , basta chamar o método estático getInstrumentation() na classe InstrumentationRegistry :

 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()
 

Construa e teste localmente

Para os casos de uso mais comuns, use o Atest .

Para casos mais complexos que exigem personalização mais pesada, siga as instruções da instrumentação .