Alura > Cursos de Mobile > Cursos de Android > Conteúdos de Android > Primeiras aulas do curso Android parte 2: boas práticas e novos cenários de testes

Android parte 2: boas práticas e novos cenários de testes

Analisando e removendo testes desnecessários - Introdução

Eu sou Alex Felipe, instrutor aqui da Alura e vou apresentar para vocês a segunda parte do curso de testes automatizados e TDD no Android. Isso significa que, se você não fez a primeira parte do curso de teste automatizado e TDD no Android, eu recomendo que você pare o vídeo nesse momento, faça o curso, veja todo o conteúdo que foi abordado naquele curso, porque vamos acabar utilizando durante todo o curso tudo o que nós vimos anteriormente.

É claro, com novas técnicas, com novas regras de negócio e com novos desafios que veremos durante esse curso. Então, eu recomendo que você saiba todo esse conteúdo que vai ser um pré-requisito.

Mas então, o que vamos ver durante esse curso? Nesse curso, vamos implementar novas features como vimos anteriormente, só que a diferença é que essas features nem vão estar relacionadas com a tela em si, mas vão estar bem relacionadas com a regra de negócio.

Elas serão features conhecidas também como features de casos excepcionais, eu estou passando aqui um spoiler para vocês mais ou menos do que vamos implementar.

Veja que são mais ou menos umas cinco, quatro features, só que vamos ver o desafio que temos ao implementar essas features, considerando TDD, considerando que temos que fazer com que os outros testes passem também da mesma maneira e vamos ver o poder dos testes automatizados quando temos que colocar essas novas features que tem outros desafios que não estamos acostumados.

Agora que vocês sabem o que vamos acabar implementando. Da parte técnica, o que vamos ver? Da parte técnica vamos ver o seguinte: como comentei, vamos acabar colocando novas features que vão impactar em outros testes.

Então vamos acabar vendo como podemos estar lidando por exemplo quando implementamos uma nova feature que faz com que o outro teste seja impactado, ou seja, vamos aprender a colocar um código que atenda todos os casos de uso.

Dado que esperamos que todos os casos de uso funcionem, como também, vamos ver como podemos estar lidando quando colocamos um novo caso de uso, um novo teste, uma nova feature que acaba deixando outros testes inúteis, porque uma nova regra de negócio entrou e ela faz com que outras regras de negócio já não sejam mais úteis, vamos ver como podemos lidar com isso também.

Depois, vamos ver como que podemos estar fazer para lidar com testes que eles vão esperar exceptions do Java. Então ao invés de ficar validando ali uma situação, eles vão esperar exceptions do Java, vamos ver como podemos estar implementando isso também com JUnit.

Temos diversas técnicas para fazer isso, vamos ver cada uma delas e também ver as situações em que uma é utilizada, a outra não é utilizada, a qual que faz mais sentido e a qual que faz menos sentido, vamos acabar aprendendo isso também.

E por fim vamos utilizar aqui, vamos aprender outras abordagens para executar o teste, porque, a princípio, como que executamos todos os testes? Utilizamos aqui o nosso famoso assertEquals só que o JUnit, ele não está limitado apenas ao assertEquals ele tem diversos asserts para poder utilizar aqui dentro da própria biblioteca.

Vamos ver cada um deles e vamos ver um deles que é bem bacana e que a comunidade de testes acaba gostando bastante. Eu vou mostrar ele para vocês, espero que você esteja bem ansioso para aprender qual que é, eu também espero que você esteja bem animado para fazer esse curso e eu conto com você para continuar com o curso.

Analisando e removendo testes desnecessários - Devolvendo zero como padrão

Agora que implementamos a feature que devolve os três maiores lances, podemos continuar com as próximas. Então se descermos um pouquinho aqui no nosso documento, perceba que agora temos novas features para serem implementadas para casos excepcionais.

Então, na primeira, ele fala o seguinte: que podem existir leilões sem lances mas, que quando acontecer isso, tanto o maior, quanto o menor lance precisa apresentar o valor zero como padrão. Precisamos garantir que nosso software faça isso. E é isso que vamos garantir agora.

Então voltando aqui no nosso projeto, vamos criar agora um teste para verificar isso. Então vamos criar aqui um teste, “@Test” e o primeiro deles vai ser para garantir quando formos pegar o maior valor e não tiver nenhum lance.

Então vai ser “deve_DevolverValorZeroParaMaiorLance_QuandoNãoTiverLances()” é isso que vamos fazer. Agora o que nós precisamos testar? Precisamos pegar o nosso leilão que não vai ter nenhum tipo de lance, então precisamos montar um cenário.

E precisamos aqui, pedir o maior lance, pedimos o maior lance, falamos que é o maior lance devolvido. Eu até cliquei aqui antes de colocar o nome, “maiorLanceDevolvido” e só precisamos o “assert”

Então o assert vai ser um “assertEquals” que vai verificar se o “maiorLanceDevolvido”, equivale a zero, eu vou colocar aqui o “DELTA” e vamos ter aqui o nosso teste. Agora só precisamos executar.

Eu vou executar a nossa classe de teste como está colocando aqui em cima, executei aqui e nesse teste que criamos deu uma falha, falando o seguinte: que esperamos o valor zero mais esse -Infinity, é justamente porque aquela nossa implementação inicial, consideramos o valor inicial como Infinity.

Se entrarmos aqui na nossa classe do leilão vamos ver como é que ela está, aqui inicialmente ele está com o valor Negative Infinity como podemos estar resolvendo isso? Anteriormente estávamos considerando como o menor valor possível para poder calcular o maior lance aqui para nós, mas podemos perceber que, por exemplo, esse menor lance que temos aqui pode ser considerado como valor zero.

Dado que, não estamos trabalhando com valores negativos, podemos estar considerando como o menor valor possível o valor zero e também ele seria considerado o valor padrão.

Com essa pequena modificação, vamos fazer a execução de todos os testes e ver como que é o comportamento do nosso software, então “Shift + F10”, ele passou com apenas essa modificação, nós não precisamos ficar se preocupando se teve algum outro tipo de problema,

Dado que, os nossos testes já garantem para nós que o comportamento esperado ocorre da maneira como já planejamos, da maneira como a regra de negócio que fizemos até o momento espera. Então não precisamos nos preocupar com apenas essa modificação, Já conseguimos garantir.

Agora nós podemos passar para o próximo caso de uso, que é para situações que queremos pegar o menor lance, dado que o valor padrão que esperamos é zero, quando não tem nenhum lance.

Então nós vamos aqui, criamos mais um teste, eu vou aumentar aqui o código “ Ctrl + Shift + F12”, “@Test” e aqui eu vou fazer um “public void deve_DevolverValorZeroParaMenorLance_QuandoNaoTiverLances”. Esse é o próximo teste que nós temos que garantir.

Da mesma maneira como fizemos anteriormente, nós usamos aqui o “CONSOLE”, pegamos o menor lance agora, então “getMenorLance” e atribuímos para uma variável que vai ser a “menorLanceDevolvido” só precisamos fazer o “assertEquals” que vai ser exatamente o mesmo assertEquals, só vai mudar que vamos pegar para o menor lance, faz um “DELTA” aqui e temos aqui o nosso teste.

Vamos executá-lo novamente e vamos ver o que acontece, executou e deu um problema nesse nosso teste que criamos. Ele está falando que devolvemos o Infinity, então uma solução aqui, a primeiro momento, seria colocar como valor padrão 00, dado que funcionou aqui para o maior lance. Então podemos colocar aqui como “0.0” e vamos testar novamente.

“Shift + F10”, ele colocou aqui e funcionou o nosso teste, mas, como estamos vendo aqui, ele impactou em outros testes que estão relacionados ao menor lance, que é no caso quando temos lances em ordem crescente, ordem decrescente e quando tem apenas um único lance.

Por que ele impactou? Porque o cálculo que estávamos utilizando era o seguinte: se pegarmos aqui o cálculo do menor lance considerávamos que qualquer tipo de valor que entrasse aqui para o nosso leilão, ele sempre seria menor do que o nosso menor lance sendo que agora não tem como ele ser menor do que o lance se ele não for negativo.

Então por exemplo, como foi esse caso que tínhamos um lance aqui, eu vou até entrar aqui no nosso teste para vermos ele aqui, entrei no teste, colocávamos um lance de 100 e o outro lance de 200, eles nunca serão menores do que zero. Então, por isso que essa pequena modificação, ela não funciona para nós.

Então como que podemos estar fazendo para resolver isso? Temos diversas maneiras para poder estar lidando com esse tipo de situação e manter o comportamento esperado para todos os cenários de teste que nós queremos que passe.

[05:01] E uma delas é a seguinte, já que nós queremos que mantenha esse valor padrão zero, nós vamos deixar como valor padrão zero. Só que quando nós recebemos apenas um único lance, nós vamos tratar esse primeiro lance de uma maneira especial.

Então vamos fazer o seguinte, se você for o primeiro lance, então pegamos nossa lista de lances e verifica o tamanho, se for um, esse aqui é o nosso primeiro lance, se você for o nosso primeiro lance, nós queremos que você seja atribuído como o maior e o menor lance. Já queremos que ele faça isso, sendo que ele já vai ser isso mesmo, dado que não tem nenhum outro parâmetro para compararmos, independente do lance.

Então o que podemos fazer? Podemos pegar o valor do lance que estamos pegando aqui embaixo, colocar logo aqui como Inicial aqui mesmo, não tem nenhum problema e dado esse valor que temos aqui em cima, podemos atribuir como “maiorLance”, então “valorLance” e também, como “menorLance”.

Podemos estar fazendo isso e sempre vai garantir que ele não vai manter o valor zerado caso ele receba um lance aqui para nós. Ele vai manter o primeiro lance que ele recebeu, dessa maneira, também se pensarmos em uma otimização de código, não precisamos fazer esses outros passos, que é no caso ordenar a nossa lista de lances ou então calcular o maior ou menor, dado que, já calculamos o maior e menor lance e só tem apenas um único lance. Não precisamos fazer essas próximas etapas.

O que isso significa? Significa que podemos fazer um “return” aqui que não tem nenhum problema. Então com esta modificação aqui, nós já vamos ver se atende todas as necessidades considerando a parte dos valores iniciais, que é zero para o maior e menor lance e também esses outros casos que deram problema.

Nós vamos testar agora, então, “Shift + F10” e vamos ver o que acontece, nós rodamos e tudo funcionou da maneira esperada. Então perceba que teste automatizado é muito benéfico, porque por mais que nós façamos um mínimo de alteração, por mais que nosso código cresça, por mais que o nosso software comece a apresentar novos comportamentos, são eles que vão garantir tudo que precisamos que seja garantido.

Como foi esse caso aqui que uma pequena modificação impactou em outras, tivemos que repensar e colocar uma nova solução que atenda todas as necessidades, que foi essa daqui que fizemos. Então agora fizemos essa primeira implementação, a seguir vamos continuar a fazer as próximas.

Analisando e removendo testes desnecessários - Invalidando testes

Agora que implementamos a primeira feature excepcional, podemos seguir com a segunda. Nela diz o seguinte que o leilão não pode receber um lance que seja menor que maior de todos e faz todo o sentido, dado que, dentro de um leilão, quando temos uma nova proposta de lance, ela precisa ser maior do que o último lance. Então, é justamente isso que vamos testar no nosso software.

Então, entrando aqui no Android Studio, vamos começar criando o nosso teste, então qual que vai ser o teste que vai garantir isso? Vamos colocar aqui um “@Test” primeiro, que é aquela assinatura que estamos acostumados, que é o “public void” e agora precisamos definir o teste que vai fazer isso.

Perceba o seguinte, que sempre trabalhávamos em cima de uma afirmação, de alguma coisa que deveria acontecer no nosso software, só que agora não pode estar acontecendo uma adição de um lance, dado que, ele seja menor do que o maior lance que foi dado.

Então nesses casos que estamos trabalhando em cima de uma negação, uma técnica que podemos estar utilizando para nomear o teste, é fazendo o seguinte, é colocando o “naoDeve” inicialmente.

Então essa é uma técnica que podemos estar usando, quando trabalhamos em cima de uma negação de algum caso excepcional. Então o que que não deve acontecer nesse caso? Não deve adicionar o lance, “naoDeve_AdicionarLance” e agora só temos que colocar quando isso não pode acontecer, que é justamente “_QuandoForMenorQueOMaiorLance()”

Então perceba que agora podemos estar trabalhando em cima dessa técnica, quando estamos trabalhando em cima de negações. Podemos usar essa técnica, mas também nada impede de você manter o deve.

Então como seria o caso se fosse apenas o deve? poderia ser deveRejeitarLance, também seria uma técnica válida. Só que no caso, quando trabalhamos em cima do naoDeve, fica bem nítido o que que está acontecendo aqui no nosso teste, que está trabalhando em cima de uma rejeição, em cima de alguma coisa excepcional, que não pode acontecer.

Então por isso que eu também até prefiro esse tipo de técnica, fique à vontade de usar da maneira que preferir. Definimos aqui o nome, aprendemos essa nova técnica, precisamos agora só criar o teste e ver como é que ele funciona.

Então, como nós criamos o teste? A partir do nosso leilão, nós propomos aqui o novo “Lance”, então, a partir do usuário “Alex” mesmo, eu vou colocar um lance de “500” reais. Eu vou dar um “Ctrl + D” para facilitar aqui a nossa vida e vou criar aqui um novo usuário, então o novo “Usuário” vai ser a “Fran” como estamos acostumados e esse usuário, ele vai dar aqui um valor de “400”.

Então nós montamos o cenário que não pode acontecer aqui, agora só temos que montar o nosso teste, executar uma ação esperada que, a partir do nosso leilão, precisamos ter algum tipo de parâmetro que nos indique se essa ação ocorreu, se ela não correu, o que aconteceu.

Como que poderíamos verificar isso? Uma técnica que podemos usar é verificar a quantidade de lances que foram adicionadas dentro de um leilão. Porque, por exemplo, se tiver mantido apenas um único lance, significa que funcionou, se tiver mais do que um lance, significa que deu um problema porque ele aceitou aqui um lance que é menor.

Então precisamos dessa informação, mas, veja que não temos baseando-se nos métodos públicos que foram adicionados aqui, para a nossa classe de leilão. Então podemos usar a seguinte técnica: Podemos indicar que precisamos da quantidade de lances e podemos falar que quando pedirmos essa quantidade de lances, queremos que ele devolva a “quantidadeLancesDevolvida" que é o que estamos acostumados como padrão para executar os nossos testes.

E agora que estamos indicando que ele devolva aqui um inteiro para nós, podemos usar o próprio Android Studio com o atalho “Alt + Enter” e falar para ele criar esse método para nós.

Então eu dou o Enter aqui e ele já criou o método que devolve o inteiro da maneira esperada, o que precisamos fazer agora é só uma implementação do nosso código para que devolva a quantidade de lances, realmente, de fato.

Então precisamos devolver o tamanho da nossa lista de lances que é onde está sendo computado aqui cada um dos lances que entra dentro aqui do leilão. Então, a partir da nossa lista de lances, então “lances.size();” conseguimos pegar o tamanho da nossa lista e devolver a quantidade de lances esperada.

Agora que temos a quantidade de lances, só precisamos fazer o “assertEquals()” que vai ser esperado um valor “1”, dado que, não queremos aceitar o segundo lance e vai ser parametrizado a partir do “quantidadeLancesDevolvida” então, montamos aqui o nosso teste.

Vamos rodar agora a nossa classe de teste e ver como que ele se comporta com a nossa implementação atual. Então, “Shift + F10” vamos ver o que acontece, ele rodou e justamente nesse nosso teste, ele deu uma falha, ele apresentou o seguinte, que estávamos esperando um único valor, sendo que devolveu dois.

Portanto, nosso software ele não impede esse tipo de ação e, é justamente isso que vamos implementar agora. Então, fechando aqui essa telinha aqui do JUnit e entrando aqui na nossa classe do leilão, precisamos fazer a implementação que impeça essa ação. E aonde podemos fazer isso? É justamente dessa ação de propor um novo lance.

Então quando vamos propor um novo lance, precisamos fazer algum tipo de validação que impeça essa ação de adicionar um novo lance, caso não seja válido. Então o que vamos fazer é adicionar um “if” aqui mesmo, antes da adição do lance, que vai poder verificar isso para nós.

Então esse if ele vai fazer o seguinte, ele vai pegar o nosso maior lance e vai comparar, se ele ainda for maior que o valor do lance que é um novo lance que está sendo dado, a única coisa que vamos fazer é simplesmente retornar o nosso código.

É isso que vamos fazer, dado que não queremos fazer mais nada, dado que não queremos adicionar, não queremos verificar o primeiro lance, nada. Se ele for realmente um valor, que seja menor que o maior lance, não faz sentido nenhum continuar com o código.

Então agora que implementamos, vamos rodar o teste e ver o que acontece. Então, “Shift + F10”para rodar todos os testes e, ele rodou aqui e passou nesse naoDeve_AdicionarLancequandoForMenorQueOMaiorLance que é o que criamos.

Só que veja, que, teve aqui uma falha, como ele está falando e se viermos aqui embaixo, ele falhou justamente nesse teste aqui, que é o deve_DevolverMenorLance_QuandoRecebeMaisDeUmLanceEmOrdemDecrescente por que que ele falhou nesse? Vamos observar o motivo, se só lermos essa descrição daria para entender, mas, vamos ver aqui em código o que ele falhou.

Ele está fazendo exatamente o mesmo cenário de teste que fizemos agora, que é colocar um valor que é maior de lance e depois, um outro lance que é menor. Em outras palavras, esse teste que verificava a ordem decrescente, que era outra situação que imaginávamos que faria sentido para o nosso código, ele já não faz mais sentido.

Já não faz mais sentido ter testes com ordem decrescente no nosso código, dado que, a nova regra de negócio que vimos, ela não espera esse tipo de ação, ela não aceita isso. Portanto, esse teste pode se apagar do nosso código, porque ele não vai mais ser necessário, então podemos estar apagando.

Inclusive, veja que esse outro teste aqui em ordem decrescente que fizemos para o maior lance, ele passou. Ele passou porque sim, ainda o maior lance é devolvido. Só que, novamente, ordem decrescente, agora, que dado que, nós não estamos trabalhando, por exemplo, com lances que recebem um lance menor do que o maior de todos, não faz mais sentido mantermos.

Então, podemos estar apagando aqui sem nenhum problema. Não tem nenhum problema porque esse teste já não é mais válido, inclusive, esse é um feedback bem importante para vocês.

Toda vez que você tiver uma nova regra de negócio e que tiver outros comportamentos que já são Inválidos por causa dessa nova regra de negócio, faz todo o sentido você remover esses testes. Porque toda vez que você rodar eles, eles já não terão mais valor para você, eles já não terão mais valor para o nosso código, para o que temos agora de implementação, então faz todo sentido removermos.

Agora que removemos, vamos rodar novamente todos os testes e ver qual que é o comportamento agora que é esperado, rodamos e agora tudo funciona conforme o esperado. Então, agora sim, aprendemos uma nova técnica que podemos estar fazendo para criar testes para situações em que estamos trabalhando em cima de uma negação.

E também vimos que quando criamos um teste novo, que impacta em outros teste que já existiam, mas impacta pelo fato de que, os que existiam anteriormente, já são Inválidos podemos remover eles sem nenhum problema, então essa foi a técnica que aprendemos.

Sobre o curso Android parte 2: boas práticas e novos cenários de testes

O curso Android parte 2: boas práticas e novos cenários de testes possui 107 minutos de vídeos, em um total de 38 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!

Plus

De
R$ 1.800
12X
R$109
à vista R$1.308
  • Acesso a TODOS os cursos da Alura

    Mais de 1500 cursos completamente atualizados, com novos lançamentos todas as semanas, emProgramação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

Matricule-se

Pro

De
R$ 2.400
12X
R$149
à vista R$1.788
  • Acesso a TODOS os cursos da Alura

    Mais de 1500 cursos completamente atualizados, com novos lançamentos todas as semanas, emProgramação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Luri powered by ChatGPT

    Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com Luri até 100 mensagens por semana.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

Matricule-se
Conheça os Planos para Empresas

Acesso completo
durante 1 ano

Estude 24h/dia
onde e quando quiser

Novos cursos
todas as semanas