Olá, eu sou o Alex Felipe e vou ministrar para vocês o curso Testes no Android: mocks e integrações.
Nosso objetivo é analisar e testar novos comportamentos adquiridos ao nosso aplicativo de leilão em cursos anteriores de testes de automatizados, logo, o pré requisito deste curso é o conteúdo dos cursos iniciais (Android parte 1: testes automatizados e TDD e Android parte 2: boas práticas e novos cenários de testes).
Mas quais são esses novos comportamentos?
Um deles está relacionado à nossa lista de leilão que antes adicionávamos a partir do próprio código. Agora, nós recebemos esses leilões a partir de uma API que também nos provém estes dados. Teremos, portanto, uma aplicação web que simula uma API de leilões públicos.
Nessa aplicação, conseguimos cadastrar leilões no campo de preenchimento com "Descrição" e, automaticamente, os dados são consumidos, enviados e recebidos. Se abrirmos a app novamente, veremos que ele carrega os leilões que cadastramos pela web. Este é o primeiro comportamento a ser explorado no presente curso.
Além disso, temos uma nova tela, responsável pelo cadastro de usuários, que pode ser acessada ao clicarmos na silhueta de uma pessoa localizada ao canto superior direito na tela do aplicativo. Para cadastrar os usuários, bastar selecionar +
e escolher o nome.
Agora que temos o leilão e seus usuários, podemos propor lances clicando na tela correspondente - criada nos cursos anteriores. Adicionamos um lance clicando no botão com +
e digitando o valor no campo de preenchimento. A regra que aplicamos para impedir trapaças também está operando, logo, não é possível adicionar um lance mais baixo do que o último valor proposto. Caso alguém tente, aparecerá uma mensagem de alerta.
Nosso curso consistirá, então, em analisar e aplicar testes para esses três comportamentos. Porém, teremos diversos desafios durantes os testes pois, ao lidarmos com aqueles que envolvem Android Framework, existem alguns comportamentos que nos forçam a usar testes instrumentais. Como esse tipo de teste não será abordado com profundidade, lidaremos com outras alternativas viáveis, como objetos simulados ou objetos mocks.
A respeito da integração, percebemos a necessidade de testar a comunicação entre a app e API, o que também será testada com objetos simulados e com testes assíncronos, para entendermos o desafio deste em comparação aos benefícios daquele.
O desafio será entender este lado avançado sobre testes de unidades com integração, simulando esses comportamentos supracitados. Para nos auxiliar, utilizaremos uma biblioteca famosa no mundo Java chamada Mockito.
Por ora é isto, espero que você esteja animado(a) com o conteúdo do curso, que pode se complicar as vezes, mas farei o máximo para descomplicar para você. Até mais.
Para começar, devemos abrir o Android Studio - é recomendável que você use a mesma versão, 3.1.3
, para que haja paridade gráfica entre os projetos.
Agora, precisamos acessar o projeto criado nos cursos anteriores, e que foi disponibilizado para você anteriormente. O arquivo está em .zip
e contém o projeto Android, bem como o servidor que utilizaremos.
Pressionando a tecla direita do mouse e selecionando a opção "Extrair tudo", será indicado para onde desejamos extrair - recomendo que escolha o arquivo onde está o .zip
, o \projeto\
. Abrindo o arquivo extraído, encontraremos os diretórios "Leilao" e "servidor", nossa app e servidor, respectivamente.
Uma forma de abrir o projeto no Android Studio é selecionando "Open an existing Android Studio project" e escrever o nome do arquivo na área de busca. Outra forma é deixar a janela do arquivo aberta e arrastar a pasta até o programa. Vamos executar o projeto para verificar se há algum problema; para isso damos o play com a seta verde da barra de ferramentas e o programa abrirá a janela "Select Deployment Target" e solicitará o dispositivo - neste caso, Pixel API 27
, porém é possível utilizar qualquer API que preferirmos.
Inicialmente o Studio apresentará a mensagem de que não foi possível carregar os leilões. Isso ocorre porque eles não são criados por nós, mas carregados a partir da API (nosso servidor). Sendo assim, voltemos à pasta "servidor", em que há um arquivo server.jar
, possível de ser executado com dois cliques. Entretanto, desta maneira, será exigido um Windows Task Manager para que façamos o fim da execução manualmente. É recomendável, portanto, que se execute o servidor por linha de comando no prompt do Windows ou terminal de comando do Linux ou Mac OS.
Primeiro vamos abrir o cmd, prompt de comando do Windows, na tela inicial. Devemos colocar cd
para abrir um diretório e depois colar o endereço do nosso servidor, que pode ser copiado ao selecionarmos a palavra "servidor" e, com o botão direito do mouse, clicarmos em "Copiar endereço".
Se dermos "Enter" desta maneira, não acontecerá nada, porque necessitamos antes acessar o volume D:
, onde se localiza o arquivo a ser executado. Para acessarmos o server, precisamos digitar dir
, que gerará:
O volume na unidade D é blackystudio
O Número de Série do Volume é 7416-9942
Pasta de D: Alex\mock\projeto\android-testes-mock-arquivos-inicias\servidor
30/07/2018 10:13
.30/07/2018 10:13
..30/07/2018 10:13 35.966.417 server.jar
1 arquivos(s) 35.966.417 bytes 2 pasta(s) 87.12.733.696 bytes disponíveis
Para rodarmos o arquivo -jar
, é preciso que adicionemos ao final desta última linha o comando java
indicando que o arquivo pertence à classe Java, bem como -jar
indicando o tipo de arquivo Java e o nome do arquivo, server.jar
, de modo que a linha ficarájava -jar server.jar
. Agora, ao executar, o prompt nos mostrará todos os logs
que estão sendo executados.
Uma maneira de verificar se eles estão funcionando como esperado é checar se na última linha aparece a mensagem Started LeilaoApiApplicationKt
. Notem também, que na terceira linha de cima para baixo, encontra-se a porta em que ele está rodando, 8080
, portanto, se formos até o navegador e digitarmos localhost:8080
, isto abrirá nossa API, em que adicionaremos os leilões. Para acessá-los, inclusive, basta digitarmos localhost:8080/leilao
na barra de endereço do navegador.
Nosso servidor está funcionando da maneira esperada! E se quisermos finalizá-lo, basta pressionarmos "Ctrl + C". Quando o server é finalizado, precisamos refazer os comandos para que ele execute novamente. Ao fazermos isso, perceberemos que os dados anteriormente adicionados serão mantidos.
Mas se não há banco de dados instalado, como foi possível mantê-los?
Ao executarmos o server.jar
, automaticamente surge o diretório "database", onde serão mantidos todos os arquivos. Isso foi feito desta forma para que não precisemos nos preocupar com a preparação do ambiente, e instalar diversos bancos de dados, nem termos dependências. Se abrirmos a app, no entanto, ela não carregará os leilões.
No Studio, na aba lateral esquerda, temos o projeto "Project" aberto, que contém a pasta "app", fazendo o caminho "app > java > api > retrofit > RetrofitInicializador". A constante URL_BASE
possui a mensagem http://endereco_ip_da_api/
, que deve ser preenchida com o IP do servidor. Com o atalho "Alt + F12" temos acesso ao terminal dentro do programa, e usando o comando ipconfig
, podemos consultar este IP. Ele nos levará ao endereço IPv4 192.168.20.248
, que é o endereço de nosso computador.
Copiaremos este endereço e o colaremos na nossa API juntamente com a porta 8080
, de modo que nossa URL_BASE
ficará http://192.168.20.148:8080/
. Com o atalho "Shift + F10", o Android Studio será executado, e saberemos que a app conseguiu carregar os leilões. Pronto, resolvemos nosso problema de integração!
Para cada atualização de leilão pela API, é necessário sair e entrar na app para que ela atualize as informações.
Dando continuidade ao curso, vamos explorar as novas features vistas e identificar unidades potencialmente testáveis. Como os leilões não são criados por nós, mas importados da API, vamos explorar a implementação para verificar se existe a possibilidade de criarmos algum teste. Para explorá-lo, vamos a "ui > activity > ListaLeilaoActivity", em que veremos o seguinte código:
public class ListaLeilaoActivity extends AppCompatActivity {
private static final String TÍTULO APPEAR = "Leilões";
private static final String MENSAGEM_AVISO_FALHA_AO_CARREGAR_LEILOES = "Não foi possível carregar os leilões";
private final LeilaoWebClient client = new LeilaoWebClient();
private ListaLeilaoAdapter adapter;
}
A segunda linha do código é referente à mensagem "Não foi possível carregar os leilões", anteriormente exibida. Na terceira linha, encontra-se o atributo client
representando um leilão web client, que é uma classe que abrange toda regra de negócios para carregar os leilões, seguida pelo adapter
que vimos anteriormente. Foquemos, finalmente, no fluxo da nossa aplicação:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lista_leilao);
getSupportActionBar().setTitle(TITULO_APPBAR);
configuraListaLeiloes();
}
private void configuraListaLeiloes() {
configuraAdapter();
configuraRecyclerView();
}
private void configuraRecyclerView() {
RecyclerView recyclerView = findViewById(R.id.lista_leilao_recyclerview);
recyclerView.setAdapter(adapter);
}
private void configuraAdapter() {
adapter = new ListaLeilaoAdapter(context: this);
adapter.setOnItemClickListener((leilao) -> {
vaiParaTelaDeLances(leilao);
});
}
É na configuração de onCreate()
que setamos o título dos nosso leilões. Configuramos o Adapter e o RecyclerView. Em adapter
, basta que criemos uma instância e setemos um Listener para que cada vez que um leilão for clicado, ele abra a tela de lances correspondente. Tão simples quanto, é o recyclerView
, pois basta setar o Adapter.
@Override
protected void onResume() {
super.onResume();
client.todos(new RespostaListener<List<Leilao>>() {
@Override
public void sucesso(List<Leilao> leiloes) { adapter.atualiza(leiloes); }
@Overide
public void falha(String mensagem) {
Toast.makeText(context: ListaLeilaoActivity.this,
MENSAGEM_AVISO_FALHA_AO_CARREGAR_LEILOES,
Toast.LENGTH_SHORT).show();
}
});
}
Em onResume()
, começa a ser usado nosso client
, com o método chamado de todos
, que tem a responsabilidade de pegar todos os leilões. Isto é feito implementando-se a interface RespostaListener
, que possui dois métodos, sucesso
e falha
. Atentem-se que sucesso
está recebendo uma lista de leilões (List<Leilao>
).
Percebam que o RespostaListener
lida com uma lista de generics, e é por isso que se recebe uma lista de leilões:
public interface RespostaListener<T> {
void sucesso(T resposta);
void falha(String mensagem);
}
Então, todos
implementa esta interface e nos devolve a lista de leilões quando ela estiver carregada a partir do retrofit. Notem que uma unidade que se repete e que ainda não está garantida no software é o adapter
. Precisamos garantir que este elemento atualizará a lista de leilões independentemente se ela vier da API ou de outro comportamento. Faremos, portanto, um teste com ele para verificar seu funcionamento.
Para testá-lo, vamos primeiro a ListaLeilaoAdapter
, que acessamos clicando nele e usando o atalho "Ctrl + B". Com ListaLeilaoAdapter
selecionado, daremos "Ctrl + Shift + T" para abrirmos o Creator Test, onde devemos escolher o diretório de test, segundo da lista.
Selecionando-se "OK", o teste é criado. Em seguida, criaremos também o comportamento a ser testado, que é atualizar a lista de leilões quando esta for recebida, ou seja, deve_AtualizarListaDeLeiloes_QuandoReceberListaDeLeiloes()
.
O objeto será adapter
, que precisa de uma instância, então teremos ListaLeilaoAdapter()
- notem que existe uma dependência de contexto. Uma vez que o próprio framework do Android cria o contexto, assim, é melhor mandarmos uma referência nula - null
- e observar o quanto isso impactará no teste.
Agora, nos falta apenas programar o comportamento esperado, por isso adapter
precisa atualizar a lista. Para tanto, faremos a instância de um ArrayList
com base em Arrays.asList()
. Em seguida, enviaremos a instância de Leilao()
, ou seja, de objetos a serem leiloados, neste caso "Computador" e "Console". A seguir, pegaremos esse valor para verificarmos a quantidade de leilões que teremos.
Começamos com Leilao
generics inicial porque não era garantido que existia um valor de leilão dentro do Arrays.asList()
, mas agora podemos apagá-lo, já que a conversão será feita automaticamente.
Precisamos de um valor que identifique se os leilões foram recebidos. Podemos usar a quantidade do adapter
, ou seja, Adapter.getItemCount()
, e devolvemos para um valor que conseguiremos a partir de uma comparação. Seu nome será quantidadeLeiloesDevolvida
, a partir dela executaremos o nosso teste.
Para verificar se foram enviados dois itens, teremos dois leilões no adapter
, então, para finalizar, devemos digitar assert.That(quantidadeLeilõesDevolvida, is(value: 2))
. Com isso, temos nosso teste:
@Test
public void deve_AtualizarListaDeLeiloes_QuandoReceberListaDeLeiloes() {
ListaLeilaoAdapter adapter = new ListaLeilaoAdapter(context: null);
adapter.atualiza(new_ArrayList<>(Arrays.asList(
new Leilao(descricao:"Console"),'
new Leilao(descricao:"Computador")
)));
int quantodadeLeiloesDevolvida = adapter.getItemCount();
assertThat(quantidadeLeiloesDevolvida, is(value:2));
}
Executando com "Ctrl + Shift + F10", o teste apresenta uma falha Null Point Exception na linha 56
, que representa um membro do adapter
do RecyclerView
que precisa de um contexto fornecido pelo Android, sendo que oferecemos referência nula.
Chequemos como será seu comportamento se comentarmos o notifyDataSetChanged()
. Desta forma, executando novamente com "Ctrl + Shift + F10", o teste funciona. Percebam que começamos a lidar com testes que exigem dependências das quais não temos muito controle.
Se criarmos um contexto manualmente, por exemplo, voltando à linha ListaLeilaoAdapter adapter = new ListaLeilaoAdapter(context: null)
e substituindo null
por new Context
, um gigantesco contexto será criado, e então devemos remover o comentário de notifyDataSetChanged()
.
O teste falha novamente, pois estes testes dependem de outros componentes, ou são muitos complexos de serem criados, não são trivialmente executáveis, por conta de outros sets de unidade. Considerando este contexto, começaremos a aprender técnicas que permitem executarmos estes testes de modo mais fácil, sem comprometer o código fonte.
Com aquele trecho de código comentado, carregamos a app e nossa lista não aparece, isso comprova que existem grandes riscos nesses tipos de testes, e vamos aprender a lidar com eles!
O curso Testes no Android: Mocks e integrações possui 169 minutos de vídeos, em um total de 54 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:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.