Alura > Cursos de Mobile > Cursos de Android > Conteúdos de Android > Primeiras aulas do curso Android com Espresso parte 1: teste da interface do usuário

Android com Espresso parte 1: teste da interface do usuário

Conhecendo os possíveis testes - Introdução

Olá! Eu sou Alex Felipe, instrutor da Alura, e vou apresentar para vocês a primeira parte do curso Android com Espresso parte 1: Teste de interface do usuário, uma continuação de uma série de cursos aqui da Alura:

Testes com Android

Testes de Android com Mockito

Sendo assim, é recomendável que você assista os cursos anteriores antes de iniciar este daqui, principalmente porque utilizaremos o mesmo projeto que começamos a desenvolver nestes precedentes, além de nos valermos de conceitos apresentados anteriormente.

Quando estávamos criando testes nos primeiros cursos, garantíamos diversos comportamentos esperados em nossa aplicação, mas para nossos usuários finais, sempre há alguma vulnerabilidade, e precisávamos executar a aplicação manualmente, usando o app e, se tudo funcionasse de acordo, não tínhamos esse processo automatizado, como visto nos cursos iniciais de teste.

Perceba, portanto, que o foco aqui será fazer com que esses comportamentos visuais, essa parte em que o nosso usuário vai ter de contato com aplicativo, seja garantida de maneira automatizada, e veremos que existem diversas motivações para que foquemos neste tipo de teste. Aprenderemos de antemão quais são as principais consequências quando não consideramos essas abordagens, e quais tipos de categoria de testes temos a partir dos fundamentos do ambiente Android. Veremos que não é tão simples quanto executar um teste de unidade, porque devemos garantir comportamentos que envolvem integração com outras ferramentas.

É sabido que para realizar um teste estamos suscetíveis a qualquer mudança e problemas que possam acontecer, por isso, durante esse curso, focaremos na configuração inicial ideal para esse tipo de cenário, ou seja, prepararemos um ambiente de teste que vai ser uma nova API, e conheceremos formas para aprimorarmos e conseguirmos testar tais novos comportamentos com integrações sem impactar a produção.

É possível mostrar como os testes funcionam não-manualmente a partir de uma classe de teste, neste caso ListaLeilaoTelaTest. Debruçaremo-nos sobre ela para executar todos os testes e verificar se o Android Studio está efetuando as verificações. Também focaremos na preparação do ambiente para que ele seja ideal, de modo que consigamos explorar testes com Espresso ao máximo.

O Espresso, basicamente, é uma biblioteca que poderemos verificar a partir de nossa tela disponibilizada pelo Developers do Android. Com ela, é possível fazer testes como se fossem de unidade. Neste primeiro curso, focaremos mais na preparação do ambiente ideal, enquanto no segundo (Android com Espresso parte 2: Testes de fluxos complexos), veremos essa biblioteca em detalhamento.

Espero que estejam animados com esse novo mundo de testes, que é, de fato, um mundo mais avançado, e vai um pouco além dos testes de unidade, e um pouco além de testes com a integração de alguns componentes, envolvendo fluxos de nosso usuário. É um conteúdo realmente mais pesado, mas deixamos tudo bem passo a passo para que em um segundo momento, exploremos a ferramenta do Espresso. Aguardo vocês a seguir!

Conhecendo os possíveis testes - Problema de acreditar apenas nos testes de unidade

Com nossos testes de unidade, conseguimos garantir diversos comportamentos esperados em nosso app, como propormos um novo lance que não será aceito se for menor que o anterior.

Há um detalhe ao qual devemos nos atentar. Em se tratando de testes, testes de unidade não são o suficiente para garantir que o produto seja entregue da maneira esperada ao usuário final. Ao lidarmos realmente com a integração do Android framework, isto é, para termos certeza de que a lista de leilões será carregada na tela, por exemplo, precisamos de um teste que nos garanta essa interação.

Um problema comum é que esses testes, feitos para garantir diversos comportamentos, acabam apresentando falhas na aplicação. Por exemplo, podemos ir até o Adapter da lista de leilões, e nele encontrarmos um ViewHolder, onde temos a view, ou seja, a exibição, para cada um dos elementos do RecyclerView(), e torná-las invisíveis por meio de seteVisibility(View.INVISIBLE).

ViewHolder(View itemView) { 
    super(itemView);
    itemView.setVisibility(View.INVISIBLE);
    descricao = itemView.findViewById(R.id.item_leilao_descricao);
    maiorLance = itemView.findViewById(R.id.item_leilaoi_maior_lance);
    itemView.setOnClickListener((v) -> {
        onItemClickListener.onItemClick(leilao);
    });
} 

Aqui, usamos a API 28 e a versão 3.2 do Android Studio.

Assim, se executarmos a aplicação, os leilões não aparecerão. Verificaremos agora como o teste se sairá. Para isto, separamos leilao in app, que pega o Source set de teste e executa todos eles. Se executarmos todos de uma vez, descobriremos que eles serão executados e bem sucedidos. Todavia, reparem que o produto final a ser entregue não é satisfatório, pois não entregamos o que está sendo proposto. Esse problema precisa ser resolvido nesta cobertura de testes que estamos estudando.

Neste primeiro curso, focaremos exatamente nestas situações. Mas antes de fazer as implementações ou comentar sobre outras ferramentas, aproveitarei o próximo vídeo para elucidar sobre os fundamentos de testes do Android.

Conhecendo os possíveis testes - Fundamentos de testes no Android

Antes de começarmos as implementações, é preciso entender os fundamentos de teste no ambiente Android e a importância de nossos testes de unidade, e também dos próximos testes que implementaremos no decorrer do curso.

Partindo do princípio de implementação de teste, durante os cursos, a proposta esteve relacionada a uma feature em desenvolvimento. Ao começarmos os testes, considerando a técnica de TDD (Test-Driven Development), sabemos que é muito comum criar um teste que inicialmente falhará. A partir disso, mexeremos no código fazendo as manutenções necessárias até que o teste passe com a implementação mais simples possível.

Nesta implementação, muito provavelmente alguns detalhes ficarão para trás, e por isso é preciso refatorar o código do teste. Depois da refatoração, executamos o teste novamente, e pode ser que ele passe, ou volte a falhar. Assim, começando este ciclo:

círculo de contorno vermelho com texto "falha em teste de unidade", com seta saindo dela e apontando para o círculo de contorno verde com texto "passar teste de unidade", com seta saindo e apontando para círculo de contorno azul e texto "refatorar", cuja seta aponta ao primeiro círculo, fechando assim um triângulo com "feature em desenvolvimento"

Então, como adequamos os testes de integração, ou de UI (User Interface), a esse ciclo?

Este cenário é similar aos de testes de unidade, a diferença é que os testes de unidades estão inseridos nestes de integração. Agora, faremos uso dos modelos e das regra de negócio envolvendo o Android framework, então perceberemos que o ciclo não será tão diferente.

Começaremos com o teste de UI, que falhará de acordo com o que temos do nosso negócio. Faremos com que esse teste passe ao efetuar as modificações necessárias, e então vamos refatorar e verificar novamente se haverá falhas ou não, dando continuidade ao ciclo.

círculo de contorno vermelho com texto "falha em teste de UI", com seta saindo dele e apontando um quadrado de contorno amarelo contendo dentro de si o ciclo de teste de unidade com seta saindo dele e apontando para o círculo de contorno verde com texto "passar teste de UI", com seta saindo e apontando para círculo de contorno azul e texto "refatorar", cuja seta aponta ao primeiro círculo, fechando assim um triângulo

Percebam que o Adapter foi um caso parecido ao que estamos vendo aqui. Naquele momento, deixamos os itens invisíveis e fizemos a modificação que possibilitou o sucesso do teste. Ou seja, o ciclo de testes, seja de integração (UI), ou unidade, é basicamente o mesmo.

Além desse segmento de fluxo, é importante conhecermos os tipos de teste. Relacionado ao ambiente Android, encontramos três classificações:

Testes pequenos (small tests)

Aqui, testam-se os modelos ou comportamentos isolados, como o caso em que verificamos se a lista de leilão carregava na tela ao ser buscada na API, sem precisarmos da integração propriamente dita. Esses tipos de teste acabam rodando dentro do nosso computador, de uma instância da JVM quem tem um bom tempo de resposta para nos dar os feedbacks necessários.

Testes médios (medium tests)

Usados quando queremos garantir se o nosso negócio, integrado à ferramentas ou APIs do framework, funcionam. Quando testamos a API por meio do teste instrumental de busca dos leilões, fizemos um teste de integração.

Os testes médios são um pequeno avanço dos testes de unidade. A diferença é que fazem integração dos comportamento de unidade com algum tipo de serviço, seja o banco de dados do Android, ou uma API externa, e assim por diante.

Testes grandes (large tests)

Agora, é importante entendermos o que esperamos para cada um dos testes. A tabela abaixo elucida as características de cada classe:

Tipo de testeTempo de feedbackFidelidade
small testpequenopequeno
medium testmédiomédio
large testgrandegrande

Percebam que o tempo de feedback e de fidelidade são proporcionais. Ou seja, quanto mais rápida a resposta vier, menos fidedigna ela será. Essa tabela pode ser traduzida para um gráfico em pirâmide:

no eixo x há uma seta que aponta para o lado direito e esquerdo, representando a dimensão de "Quantidade de testes", no eixo y uma seta com ponta para cima e para baixo, representando as dimensões de "Fidelidade, Tempo de execução, Manutenção e Debugging"; três blocos formam um pirâmide tendo como base os testes de unidade e o desenho de um notebook, teste de integração com desenho de um celular e, por último, testes de UI também representado por um celular

Existe uma proporção recomendada para cada tipo de teste:

Devemos realmente seguir essa proporção?

Não necessariamente. Quando temos essa vasta quantidade de small tests, a vantagem é que teremos cada regra e caso de uso de maneira isolada. Então, se um comportamento específico falhar, teremos um teste de unidade verificando e apresentando este problema. Não precisaremos de uma execução muito grande para isso.

Da mesma maneira, assim que subimos a proporção de medium, teremos um pouco de teste de integração com nosso negócio e o tempo não será tão rápido, mas não demorará para verificarmos se a integração está funcionando como esperado. Em large, garantiremos apenas a parte da tela do nosso usuários. Veremos se o fluxo está fluindo como esperado assumindo que nossos testes de unidade já estão garantindo os comportamentos iniciais.

Contudo, se focarmos menos nos large tests, teremos menor fidelidade. Então, se colocarmos um caso de uso que garante todos os cenários que desejamos com large test, podemos prejudicar o produto final. Desta maneira, essa proporção depende muito da prioridade do projeto. Então não é uma regra, é apenas uma sugestão.

A minha recomendação é que você considere o que é mais importante para o seu negócio. Cada caso de uso, cada teste, a importância é unica, e faz sentido vocês refletirem sobre o que vai ser melhor para vocês.

Sobre o curso Android com Espresso parte 1: teste da interface do usuário

O curso Android com Espresso parte 1: teste da interface do usuário possui 211 minutos de vídeos, em um total de 53 atividades. Gostou? Conheça nossos outros cursos de Android em Mobile, ou leia nossos artigos de Mobile.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Android acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas