Segmentar um exemplo de aplicativo

Esta categoria de teste de instrumentação não é muito diferente daquelas destinadas aos aplicativos Android regulares. Vale ressaltar que o aplicativo de teste que incluiu a instrumentação precisa ser assinado com o mesmo certificado do aplicativo ao qual se destina.

Observe que este guia pressupõe que você já tenha algum conhecimento no fluxo de trabalho da árvore de origem da plataforma. Caso contrário, consulte Requisitos . O exemplo abordado aqui é escrever um novo teste de instrumentação com pacote de destino definido em seu próprio pacote de aplicação de teste. Se você não estiver familiarizado com o conceito, leia a introdução aos testes da plataforma .

Este guia usa o seguinte teste para servir como amostra:

  • frameworks/base/pacotes/Shell/testes

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

Decida um local de origem

Como o teste de instrumentação terá como alvo um aplicativo, a convenção é colocar o código-fonte do teste em um diretório tests na raiz do diretório de origem do componente na árvore de origem da plataforma.

Veja mais discussões sobre localização de origem no exemplo ponta a ponta para testes de autoinstrumentação .

Arquivo de manifesto

Assim como um aplicativo normal, 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 próximo a Android.mk para seu tmodule de teste, ele será incluído automaticamente pelo makefile principal BUILD_PACKAGE .

Antes de prosseguir, é altamente recomendável passar primeiro pela 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.

A versão mais recente do arquivo de manifesto para o exemplo de alteração do gerrit pode ser acessada em: https://android.googlesource.com/platform/frameworks/base/+/main/packages/Shell/tests/AndroidManifest.xml

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.shell.tests">

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

        <activity
            android:name="com.android.shell.ActionSendMultipleConsumerActivity"
            android:label="ActionSendMultipleConsumer"
            android:theme="@android:style/Theme.NoDisplay"
            android:noHistory="true"
            android:excludeFromRecents="true">
            <intent-filter>
                <action android:name="android.intent.action.SEND_MULTIPLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="*/*" />
            </intent-filter>
        </activity>
    </application>

    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
        android:targetPackage="com.android.shell"
        android:label="Tests for Shell" />

</manifest>

Algumas observações selecionadas no arquivo de manifesto:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.shell.tests">

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 só pode instalar um aplicativo com esse nome de pacote.

Como este é um pacote de aplicação de teste, independente do pacote de aplicação em teste, um nome de pacote diferente deve ser usado: uma convenção comum é adicionar um sufixo .test .

Além disso, este atributo package é o mesmo que ComponentName#getPackageName() retorna e também o mesmo que você usaria para interagir com vários subcomandos pm por meio de adb shell .

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

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

Isso é necessário para todos os testes de instrumentação, uma vez que as classes relacionadas são empacotadas em um arquivo de biblioteca jar da estrutura separado, portanto, requer entradas de caminho de classe adicionais quando o pacote de teste é invocado pela estrutura do aplicativo.

android:targetPackage="com.android.shell"

Isso define o pacote de destino da instrumentação como com.android.shell . Quando a instrumentação é invocada por meio do comando am instrument , a estrutura reinicia o processo com.android.shell e injeta código de instrumentação no processo para execução de teste. Isso também significa que o código de teste terá acesso a todas as instâncias de classe em execução no aplicativo em teste e poderá manipular o estado dependendo dos ganchos de teste expostos.

Arquivo de configuração simples

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

Arquivo de configuração complexo

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

A configuração de teste pode especificar opções especiais de configuração de dispositivo e argumentos padrão para fornecer a classe de teste.

A versão mais recente do arquivo de configuração para a alteração do gerrit de amostra pode ser acessada em: frameworks/base/packages/Shell/tests/AndroidTest.xml

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

<configuration description="Runs Tests for Shell.">
    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
        <option name="test-file-name" value="ShellTests.apk" />
    </target_preparer>

    <option name="test-suite-tag" value="apct" />
    <option name="test-tag" value="ShellTests" />
    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
        <option name="package" value="com.android.shell.tests" />
        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
    </test>
</configuration>

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

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

Isso diz à Trade Federation para instalar o ShellTests.apk no dispositivo de destino usando um target_preparer especificado. Existem muitos preparadores de alvo disponíveis para desenvolvedores na Trade Federation 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="com.android.shell.tests"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

Isso especifica a classe de teste Trade Federation 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.

Procure aqui mais informações sobre configurações do módulo de teste

Recursos JUnit4

Usar a biblioteca android-support-test como executor de teste permite a adoção de novas classes de teste no estilo JUnit4, e a amostra de alteração do gerrit contém alguns usos muito básicos de seus recursos.

O código-fonte mais recente para a alteração do gerrit de amostra pode ser acessado em: frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java

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

@SmallTest
@RunWith(AndroidJUnit4.class)
public final class FeatureFactoryImplTest {

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

A anotação @SmallTest especificou um tamanho de teste para toda a classe de teste: todos os métodos de teste adicionados a esta classe de teste herdam esta anotação de tamanho de teste. configuração de classe de pré-teste, desmontagem de pós-teste e desmontagem de classe de pós-teste: semelhante aos métodos setUp e tearDown em JUnit4. A anotação Test é usada para anotar o teste real.

    @Before
    public void setup() {
    ...
    @Test
    public void testGetProvider_shouldCacheProvider() {
    ...

A anotação @Before é usada em métodos do JUnit4 para realizar a configuração do pré-teste. Embora não seja usado neste exemplo, há também @After para desmontagem pós-teste. Da mesma forma, as anotações @BeforeClass e @AfterClass podem ser usadas em métodos do JUnit4 para realizar a configuração antes de executar todos os testes em uma classe de teste e desmontá-la posteriormente. Observe que os métodos de configuração e desmontagem do escopo de 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 sempre, os métodos de teste devem ser públicos, não declarar valor de retorno, não aceitar parâmetros e podem gerar exceções.

        Context context = InstrumentationRegistry.getTargetContext();

Como os testes JUnit4 não exigem mais uma classe base comum, não é mais necessário obter instâncias Context via getContext() ou getTargetContext() por meio de métodos de classe base; em vez disso, o novo executor de testes os gerencia por meio do InstrumentationRegistry , onde a configuração contextual e ambiental criada pela estrutura de instrumentação é armazenada. Através desta aula, você também pode ligar para:

  • getInstrumentation() : a instância da classe Instrumentation
  • getArguments() : os argumentos da linha de comando passados ​​para am instrument via -e <key> <value>

Crie e teste localmente

Para os casos de uso mais comuns, utilize Atest .

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